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

Add keyring http endpoints #2509

Merged
merged 5 commits into from
Nov 23, 2016
Merged

Add keyring http endpoints #2509

merged 5 commits into from
Nov 23, 2016

Conversation

kyhavlov
Copy link
Contributor

@kyhavlov kyhavlov commented Nov 15, 2016

First pass at adding the keyring endpoints for #2502

@@ -79,3 +99,61 @@ func (op *Operator) RaftRemovePeerByAddress(address string, q *WriteOptions) err
resp.Body.Close()
return nil
}

// KeyringInstall is used to install a new gossip encryption key into the cluster
func (op *Operator) KeyringInstall(key string) error {
Copy link
Contributor Author

@kyhavlov kyhavlov Nov 15, 2016

Choose a reason for hiding this comment

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

Should these functions take an argument for overriding the ACL token used? Some of the other api functions do, but some don't so I wasn't sure.

Copy link
Contributor

Choose a reason for hiding this comment

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

No, but I'd q *QueryOptions and q *WriteOptionsarguments to these methods and get the token from there. It kind of sucks that there's some extra fields in those that don't matter here, but that's kind of the common signature for these. We could add a helper that errors if there are things that are not supported, but we can just document for now.

if response.Error != "" {
return nil, fmt.Errorf(response.Error)
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is just returning the first error fine for these KeyringResponses? I thought about using multierror but it didn't seem useful because you'd just get a bunch of duplicate errors ("key must be 16/24/32 length" and the like)

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah that makes sense. We could dedup them into a multierror maybe so you can tell if you have a handful of problems vs. having to run several times, since a short list would be super useful.

@slackpad slackpad added this to the 0.7.2 milestone Nov 18, 2016
Copy link
Contributor

@slackpad slackpad left a comment

Choose a reason for hiding this comment

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

Looks good - put a few comments in the review!

if response.Error != "" {
return nil, fmt.Errorf(response.Error)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah that makes sense. We could dedup them into a multierror maybe so you can tell if you have a handful of problems vs. having to run several times, since a short list would be super useful.

@@ -291,6 +291,10 @@ func (s *HTTPServer) registerHandlers(enableDebug bool) {
s.handleFuncMetrics("/v1/kv/", s.wrap(s.KVSEndpoint))
s.handleFuncMetrics("/v1/operator/raft/configuration", s.wrap(s.OperatorRaftConfiguration))
s.handleFuncMetrics("/v1/operator/raft/peer", s.wrap(s.OperatorRaftPeer))
s.handleFuncMetrics("/v1/operator/keyring/install", s.wrap(s.OperatorKeyringInstall))
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 thinking we can get rid of these /verb suffixes in the URLs and use HTTP verbs for everything:

GET /v1/operator/keyring -> list keys
POST /v1/operator/keyring -> Install a key
PUT /v1/operator/keyring -> use a key
DELETE /v1/operator/keyring -> remove a key

Still not super REST-y since we don't have the key in the path, but looks more REST-y and keeps the API a little smaller.

return nil, nil
}

var args structs.KeyringRequest
Copy link
Contributor

Choose a reason for hiding this comment

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

This has extra fields that we wouldn't ever want to plumb directly (there's currently a panic() in the internal endpoint handler that we should change to an error if the Op isn't understood), so I'd make a simple unexported struct (define in here is fine) and a local string for the token and use those. There's stuff we don't use in this big struct so it's confusing to accept that here.

t.Fatalf("err: %s", err)
}

for _, response := range listResponse.Responses {
Copy link
Contributor

Choose a reason for hiding this comment

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

Length check here?

t.Fatalf("err: %v", !ok)
}

// Check that we get both a LAN and WAN response, and that they both only
Copy link
Contributor

Choose a reason for hiding this comment

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

Didn't check a WAN vs. LAN (prolly count and compare at the end).

Available in Consul 0.7.2 and later, the keyring remove endpoint supports the
`PUT` method.

#### PUT Method
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a DELETE.

@@ -43,6 +43,26 @@ type RaftConfiguration struct {
Index uint64
}

// KeyringOpts is used for performing Keyring operations
type KeyringOpts struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd make this an unexported struct keyringRequest since it's not part of your interface for the actual API functions.

@@ -79,3 +99,61 @@ func (op *Operator) RaftRemovePeerByAddress(address string, q *WriteOptions) err
resp.Body.Close()
return nil
}

// KeyringInstall is used to install a new gossip encryption key into the cluster
func (op *Operator) KeyringInstall(key string) error {
Copy link
Contributor

Choose a reason for hiding this comment

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

No, but I'd q *QueryOptions and q *WriteOptionsarguments to these methods and get the token from there. It kind of sucks that there's some extra fields in those that don't matter here, but that's kind of the common signature for these. We could add a helper that errors if there are things that are not supported, but we can just document for now.


A JSON body is returned that looks like this:

```javascript
Copy link
Contributor

Choose a reason for hiding this comment

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

It might be nice to add an endpoint here (or in the API client based on this) that summarizes the keys that have been successfully installed everywhere and are safe to switch to. Probably not in this pass, but it would be nice to know as an operator in a very high level way "this key is good to go".

@kyhavlov
Copy link
Contributor Author

Addressed comments, should be ready for another look

Copy link
Contributor

@slackpad slackpad left a comment

Choose a reason for hiding this comment

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

Just a couple trivial things and this is good to commit.

@@ -43,6 +43,26 @@ type RaftConfiguration struct {
Index uint64
}

// keyringRequest is used for performing Keyring operations
type keyringRequest struct {
Key string `json:",omitempty"`
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you need the omitempty for anything?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can't remember why I added this - it's the only field in the struct and we only ever decode to it, so there's no reason for it to be in there

t.Fatalf("bad: %d", len(responses))
}

// WAN
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this order deterministic?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it's consistent; here we call executeKeyringOp with wan = true, then with wan = false, and in this test we always get back the wan reply first.

into the cluster. There is more information on gossip encryption available
[here](/docs/agent/encryption.html#gossip-encryption).

The register endpoint expects a JSON request body to be PUT. The request
Copy link
Contributor

Choose a reason for hiding this comment

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

These descriptions all say PUT - need to update with the right verbs.

@slackpad
Copy link
Contributor

LGTM

@kyhavlov kyhavlov merged commit dcdadd0 into master Nov 23, 2016
@kyhavlov kyhavlov deleted the f-keyring-api branch November 23, 2016 01:10
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.

2 participants