Skip to content

(PUP-3526) Add configurable prefix for CA routes #3464

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

Merged

Conversation

rlinehan
Copy link
Contributor

@rlinehan rlinehan commented Jan 9, 2015

Restructure the CA endpoints to allow for a configurable url prefix, separate from the master url prefix.

@rlinehan
Copy link
Contributor Author

rlinehan commented Jan 9, 2015

This is blocked by #3444 and will need to be rebased once that goes in.

@puppetcla
Copy link

CLA signed by all contributors.

"certificate" => :ca,
"certificate_request" => :ca,
"certificate_revocation_list" => :ca,
"certificate_status" => :ca
Copy link
Contributor

Choose a reason for hiding this comment

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

We need the plural of this too right? "certificate_statuses"

@rlinehan rlinehan force-pushed the feature/master/PUP-3526-ca-api-prefix branch from ec1e1f8 to 2a9ba69 Compare January 15, 2015 19:33
@rlinehan
Copy link
Contributor Author

Rebased on top of merged-to-master PUP-3645. This should be ready to go now.

any.
chain(ENVIRONMENTS, INDIRECTED)
end

def self.ca_routes
Puppet::Network::HTTP::Route.path(%r{v1}).any.chain(INDIRECTED)
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm wondering if it's going to be problematic at all to have these coupled together in a file named after the version of the master's (but not the CA's) API.

Maybe I'm overthinking it but what happens if we need to bump CA to v2? Would we make the change in this file and leave it as http/api/v3?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a good question. I think it's sort of weird right now because both the CA prefix at v1 and the master prefix at v3 end up in the same place - IndirectedRoutes. Other than here, the only place I can think that makes sense to define these would be directly in http/api.rb.

If we were bumping the CA routes to v2, then presumably it would be because we were separating them out to no longer use IndirectedRoutes, in which case it seems like it would make more sense to define them in their own file.

Choose a reason for hiding this comment

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

This is going to sound ridiculous but I wonder if it wouldn't make sense to go ahead and have api/master/v3.rb and api/ca/v1.rb now. It's ridiculous because those namespaces would only have like 3 lines of code in them, but I kind of think it might still be worth it because otherwise the v3.rb file doesn't seem like an intuitive place to look for the v1 CA routes... :( I could survive with it like this but I think I might have a slight preference for going ahead and breaking it out now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This makes sense to me... my only question is where should the indirected_routes.rb file live?

Choose a reason for hiding this comment

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

I think that with the minor refactors we discussed at various points in the PR comments, we could end up in a state where IndirectedRoutes doesn't contain any references to any version strings. If that's the case then we could put it in the api dir or even the parent dir of that, whichever seems like a better fit.

@kylog
Copy link

kylog commented Jan 16, 2015

A fix for the spec failure has been merged in. Kicking travis to confirm.

{ :acl => "#{ca_url_prefix}/v1/certificate/", :method => :find, :authenticated => :any },
{ :acl => "#{ca_url_prefix}/v1/certificate_request", :method => [:find, :save], :authenticated => :any },
{ :acl => "#{master_url_prefix}/v3/status", :method => [:find], :authenticated => true },
{ :acl => "#{master_url_prefix}/v3/environments", :method => :find, :allow => '*', :authenticated => true },

Choose a reason for hiding this comment

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

Do you think it might be worth sorting these lines such that the CA ones are all grouped together, separate from the master ones?

@haus if we were to do that would it cause any more or fewer packaging/upgrade concerns?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorting them such that CA ones are grouped together makes sense to me; I didn't know how much it mattered and figured I'd just leave it as is with the comment about auth any.

Copy link
Contributor

Choose a reason for hiding this comment

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

@cprice404 since we're just scrapping and replacing this file during 3 => 4 upgrades, i'm not concerned here. Future upgrades within the 4 series will go fine, with any changes being handled by the package manager and user.

Choose a reason for hiding this comment

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

@rlinehan ah, that makes sense about grouping them by the comment / auth level. If we do that we might as well change it so that for each one of the different comment sections, the ca routes are always at the top or the bottom of the individual section maybe? I'm good w/whatever you think is best, not a big deal.

@cprice404
Copy link

I'm done with initial review; will pull the code down and play with it a bit. Looking good, just a few minor organizational questions / comments.

@nwolfe
Copy link
Contributor

nwolfe commented Jan 20, 2015

👍 verified with agent and CLI tools using both/neither/combinations of the prefixes.


it "should include the correct url prefix if it is a ca request" do
request.stubs(:indirection_name).returns("certificate")
handler.class.request_to_uri(request).should == "#{ca_url_prefix}/certificate/with%20spaces?environment=myenv&foo=bar"
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably not a big deal but "environment" is invalid for "certificate", right? But then again so is "foo" I guess and I suppose the validation isn't intended to work at the level of URI parameters anyway...

Choose a reason for hiding this comment

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

No, environment is required for all indirector requests. Even the ones that don't use it for anything. (Spoiler alert: we should not carry that over to v2 of the CA API :) )

Copy link
Contributor

Choose a reason for hiding this comment

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

Does this mean that external HTTP API callers to the CA v1 certificate* endpoints will be required to include "?environment=" or, if it is absent at that level, will some default be substituted to make the indirector happy?

Choose a reason for hiding this comment

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

Requests originating from the agent will include the environment query parameter, because all agent URLs are constructed via the indirector. For the Rack/Webrick masters, the requests will fail if this parameter is not provided.

For the Puppet Server CA endpoints, I suspect that it would be acceptable to ignore this query parameter rather than returning a failure response, but that is a question for product, and is orthogonal to this PR.

We should not expect the agent to stop sending this parameter until there is a significant rework of the client-side code that involves removing the indirector from the process of constructing the URLs.

Copy link
Contributor

Choose a reason for hiding this comment

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

That's fine. I don't see a problem there, mostly curious about what the expected behavior would be for CA v1. I agree it is orthogonal to this PR, but I agree with you that having Puppet Server's CA just "ignore" the environment for the CA v1 endpoints seems reasonable.

Copy link
Contributor

Choose a reason for hiding this comment

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

👍 to ignoring the parameter

@rlinehan rlinehan force-pushed the feature/master/PUP-3526-ca-api-prefix branch from 9a583f8 to a7894fe Compare January 21, 2015 22:20
@rlinehan
Copy link
Contributor Author

@cprice404 added some commits based on your comments.

@cprice404
Copy link

+1 from me.

I'm going to pull the code down and play with it a bit, but unless anything jumps out at me from that, I'll plan on merging this on Friday or so. ping @joshcooper @hlindberg @kylog in case you guys have any interest in further review before we merge.

@rlinehan
Copy link
Contributor Author

Should I squash some of these commits, or is it fine as is?

@cprice404
Copy link

@rlinehan maybe let's wait and squash on Friday before we merge?

@rlinehan
Copy link
Contributor Author

@cprice404 sounds good.

@cprice404
Copy link

I pulled the latest code down and attacked it with curl for a while; lgtm

@joshcooper
Copy link
Contributor

@rlinehan @cprice404 Thinking out loud here... why do we need a prefix? As in, doesn't trapperkeeper know when a catalog request comes in, it should be dispatched to the puppetmaster, etc? Why do we need the additional prefix and the added configuration?

@joshcooper
Copy link
Contributor

@rlinehan @cprice404 ok, I read the ticket, that helps, but I am still surprised that we're exposing this data to the agent as it seems like an implementation detail for how to retrieve something. For example, suppose the agent makes a request for a node information, and with this PR, it'd be under the puppet prefix. But in a future release, we move that to a different trapperkeeper app. Now we need to update all REST clients...

@hlindberg
Copy link
Contributor

@rlinehan @cprice404 @joshcooper Agree with Josh - the indirection is better done on the server side - no changed URLs on agents. If we want to also be able to redirect agents wouldn't using HTTP 30x responses be the way to do that? (But that would be for other reasons than the original "do not squat on the server's '/' namespace")

@camlow325
Copy link
Contributor

My understanding has been that we're trying to move to a model where each service has a mount point that can be set via configuration -- not requiring code changes -- like what is afforded by https://github.com/puppetlabs/trapperkeeper-webserver-jetty9/blob/master/doc/webrouting-service.md. We could treat legacy Puppet as a special case that avoids this pattern for the sake of maintaining shorter-term compatibility (along with not addressing the aforementioned problems around the top-level environment in URL paths and squatting on the server's '/' namespace). This wouldn't seem like a good long-term solution, though, and essentially what I had thought had led to this whole set of work around redoing the URL paths for Puppet 4.0.

One of the major benefits that I see to having the top-level service mount point be configurable both from the server and client side is the increased level of control given to users. For example, I could see where some users might want to take advantage of the configurable prefix as part of their load-balancing scheme. For example, users might want to include a top-level "region" path in the mount point which is set for agents as appropriate for the region in which they reside, e.g., some would make requests to "/americas/puppet/..." whereas others would make requests to "/europe/puppet/...", and the load-balancer upstream would use that context from the prefix to redirect to the appropriate masters. In this model, it would be possible for the master_url_prefix on agents to be different as compared to the master.

Hardcoding the mount points into the implementation with no external configurability wouldn't seem to be progressing the implementation forward.

One could ask the question about why we're not going further by making each of the endpoints in legacy Puppet independently configurable - e.g., by codifying a catalog_url_prefix, report_url_prefix, and others in anticipation that these may become standalone services at some point. This would probably be premature, though, if the strategy around further decomposing Puppet into more discrete services hasn't been worked out. Although it may imply that further service decomposition in the future would necessitate a new round of breaking configuration changes for the server and clients.

In short, I'm good with the overall direction of the implementation captured in this current set of PRs.

@cprice404
Copy link

@joshcooper @hlindberg fair questions. Here's what I'd say:

  • We can probably make a guarantee that the default values for these prefixes will never change from the values we're populating them with now.
  • I would expect that in 99.99% of cases a user would not modify these settings.
  • On the Puppet Server side, all web apps will always be mounted at a configurable prefix, so that we have maximum flexibility for combining web apps in a single web server without risking URL collisions. Therefore, it seems like it would be short-sighted to not at least allow the configuration to be made on the client. I can imagine a future world where we support something like mounting two versions of puppet on a single server to help make it possible for people to upgrade their agents to the latest puppet version incrementally, in which case someone might choose to mount the different versions at, e.g., /puppet4 and /puppet5. The agents would need to be able to be configured to hit the correct web apps in a case like that. (It's also possible that for that specific use case, we could just have a single /puppet app on the server and have it use an HTTP header from the agent to deal with routing the request accordingly, so I'm just using this as a general example.)

In short, I think that making the prefixes configurable on the agent gives us the maximum amount of flexibility going forward, even if these settings end up almost never being used.

I'd be willing to entertain a conversation about hard-coding the prefixes on the agent, but my current opinion is that the tradeoff could theoretically paint us into a corner in the future that I feel that this solution avoids.

@cprice404
Copy link

@joshcooper also, since we will now have versioned URLs, we can make sure that in the future we still support things like /puppet/v3/catalog (via a redirect or whatever other mechanism we choose), even if the canonical endpoint has moved to /puppet-compiler/v1/catalog, etc.

@joshcooper
Copy link
Contributor

I think we're all in violent agreement that the server should allow REST endpoints to be mapped to services in configuration as outlined in https://github.com/puppetlabs/trapperkeeper-webserver-jetty9/blob/master/doc/webrouting-service.md

I'm not 100% sold on the argument that the load-balancer might segregate traffic to geographically different locations based on a URL prefix. I think more likely is that clients are configured to talk to their "local" master either by changing the server property and/or using SRV records.

If we were to allow REST endpoints to be configured on the client, then I'm not a fan of having a prefix setting, as it seems very specific to our implementation of how REST URLs are constructed. I'd prefer having an explicit URL, e.g. catalog_url=puppet:///puppet/v3/catalog. That way everything about the path is configurable. Also, it makes it possible for the client to use a "newer" versioned endpoint without changing code.

@cprice404
Copy link

If there were a newer version of an endpoint available, it would probably be because there were API changes, in which case the client code would most likely need to be modified anyway. That also seems like a significantly more invasive change to me, and seems like it would jeopardize the Puppet 4.0 target dates.

Given that what we're roughly shooting for here is a way to split out the monolithic HTTP API into more service-specific namespaces, the prefix approach seems like a fairly simple / standard way to handle it... perhaps we should schedule a meeting of interested stakeholders to hash this out, though... it seems like it's going to be challenging to come to a consensus over github comment threads...

@cprice404
Copy link

Also, just to clarify, I don't necessarily think that the goal is "to allow REST endpoints to be configured on the client". It's more like "allowing REST endpoints to be namespaced". I know that's not necessarily a black-and-white distinction, but I'm just saying that I'm not advocating for 100% configurability of the full URL... I think that the majority of the URL construction should be hard-coded for a given client version.

@cprice404
Copy link

One other random thought... in the world of today, we are using these settings to determine the URL namespaces for the Rack/Webrick server implementations, as well as for the client. So, even if we decided to change how we expose this stuff for the client, we will still need these for the server (unless we decide to just hard-code them).

@cprice404
Copy link

we just had a meeting to discuss this comment thread. I'm going to update the jira ticket with my interpretation of the outcome of that meeting if anyone is interested, but the tl;dr is that we're basically OK with this going in as-is. I'll leave it open for another day or so in case anyone wants to raise any last-minute objections, but, failing that, we'll merge it.

This commit restructures the CA endpoints to allow for a url
prefix '/ca', separate from the master url prefix.

Split the api/ directory into master/ and ca/, with master/ having v2/ and
v3/, and ca/ having v1/, to match the split of CA routes from master routes.

Move indirected_routes.rb and indirection_type.rb under api/ rather than
api/v3, since they are used by both the ca/v1 and master/v3 routes.

Also, hardcode master and CA url prefixes, rather than allowing them to be
configurable. There was no clear user need for having these be configurable
settings, and it was determined that it was not worth the extra effort of
supporting an a new setting.
@rlinehan rlinehan force-pushed the feature/master/PUP-3526-ca-api-prefix branch from a625926 to 0f044d7 Compare January 23, 2015 23:37
There are now two ways to have a request get to v3/indirected_routes:
`/puppet/v3` and `/ca/v1`. Thus, a request to `/puppet/v3/certificates` would
be routed to indirected_routes and could be handled successfully, although
issues would probably come up around authorizing the request. Such a request
is incorrect - it has the wrong url prefix - and we should say so.
Previously, the HTTP::Handler spec tests defined a HandlerTesting class. This
commit separates it into its own helper so it can be reused in other tests.
Previously, all of Puppet's routes were defined separately in the Webrick and
Rack REST interfaces. This was okay when all that was being registered was the
v1 and v2 routes. However, with the CA routes now separated from the master
routes, there is quite a bit more logic there, and it is unwieldy (and hard to
test) with it defined in both places.

This commit defines the CA and master routes in one place, so that only
ca_routes and master_routes have to be registered for each webserver.
Make the default CA url prefix '/puppet-ca', rather than '/ca'. Since the
master url prefix is '/puppet', and since the routing will match '/puppet-ca'
to '/puppet', this also means tweaking how we register routes, so that the
prefix is registered with a slash on the end and the version strings do not
begin with slashes.
Move all CA rights together. Also reorder the example auth.conf to match the
order of default_acl. Add an entry for /puppet/v3/status, which was in
default_acl but missing from the example auth.conf, since the example
auth.conf is supposed to match the default ACLs.
@rlinehan rlinehan force-pushed the feature/master/PUP-3526-ca-api-prefix branch from 0f044d7 to 80a108f Compare January 23, 2015 23:39
@rlinehan
Copy link
Contributor Author

Per continued discussion on PUP-3526, we decided that it wasn't worth the effort to support settings for the master and ca url prefixes, and it would be better to remove them. I've updated this so that he url prefixes are now constants. I've also squashed some of the commits together, so that this is a bit cleaner. It should be ready to go.

@cprice404
Copy link

@joshcooper @kylog @hlindberg I'm going to go ahead and get this merged in because it's blocking some things. Happy to revisit any of the details if any questions come up.

cprice404 added a commit that referenced this pull request Jan 24, 2015
…-prefix

(PUP-3526) Add configurable prefix for CA routes
@cprice404 cprice404 merged commit 6438c72 into puppetlabs:master Jan 24, 2015
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.

9 participants