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

Adding Evict method #693

Merged
merged 12 commits into from
Feb 4, 2019
Merged

Adding Evict method #693

merged 12 commits into from
Feb 4, 2019

Conversation

marcosy
Copy link
Contributor

@marcosy marcosy commented Jan 25, 2019

Pull Request check list

  • Commit conforms to CONTRIBUTING.md?
  • Proper tests/regressions included?
  • Documentation updated?

Affected functionality
Agent "de-attestation"

Description of change
Adding new Evict method for "de-attesting" an already attested node given its spiffeID

Which issue this PR fixes
Fixes #27

Signed-off-by: Marcos G. Yedro <marcosyedro@gmail.com>
Signed-off-by: Marcos G. Yedro <marcosyedro@gmail.com>
Signed-off-by: Marcos G. Yedro <marcosyedro@gmail.com>
Signed-off-by: Marcos G. Yedro <marcosyedro@gmail.com>
Signed-off-by: Marcos G. Yedro <marcosyedro@gmail.com>
Signed-off-by: Marcos G. Yedro <marcosyedro@gmail.com>
Signed-off-by: Marcos G. Yedro <marcosyedro@gmail.com>
Signed-off-by: Marcos G. Yedro <marcosyedro@gmail.com>
Signed-off-by: Marcos G. Yedro <marcosyedro@gmail.com>
Copy link
Member

@azdagron azdagron left a comment

Choose a reason for hiding this comment

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

Thanks for this! I was a little nit-picky, please feel free to push back on any of these that seem unreasonable :)

}

// make sure SPIFFE ID is well formed
c.SpiffeID, err = idutil.NormalizeSpiffeID(c.SpiffeID, idutil.AllowAny())
Copy link
Member

Choose a reason for hiding this comment

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

maybe idutil.AllowAnyTrustDomainAgent()?

}

func (EvictCLI) Synopsis() string {
return "De-attest an agent givent its spiffeID"
Copy link
Member

Choose a reason for hiding this comment

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

"Evicts an attested agent allowing it to re-attest"? I'm not sure what the right synopsis is :)

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! will standardize on "evict" name rather than "de-attest"

}

if !evictResponse.DeleteSucceed {
fmt.Println("Failed to de-attest agent")
Copy link
Member

Choose a reason for hiding this comment

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

Failed to evict agent? Also maybe consider sending to STDERR and exiting with a non-zero status.

fmt.Println("Failed to de-attest agent")
}

fmt.Println("Agent de-attested successfully")
Copy link
Member

Choose a reason for hiding this comment

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

"Agent evicted successfully"?

c := &EvictConfig{}

f.StringVar(&c.RegistrationUDSPath, "registrationUDSPath", util.DefaultSocketPath, "Registration API UDS path")
f.StringVar(&c.SpiffeID, "spiffeID", "", "The SPIFFE ID of the agent to evict (core identity)")
Copy link
Member

Choose a reason for hiding this comment

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

what's the "core identity" part for?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My intention was to make it clear that the spiffe ID that should be used here is the true attested node spiffeID, and not the one that the user has assigned.

For example this one spiffe://example.org/spire/agent/join_token/the_token instead of spiffe://example.org/host.

I think it is a good idea to replace it by the term "agent identity" as suggested by @evan2645 in the comment below

ctx := context.Background()
s.createAttestedNode(ctx, spiffeIDToRemove)
evictResponse, err := s.handler.EvictAgent(ctx, evictRequest)
s.NoError(err)
Copy link
Member

Choose a reason for hiding this comment

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

this should either be an s.Require().NoError() or something like:

if s.NoError(err) {
    s.True(...)
}

Otherwise the test case will panic when accessing members of the nil response.

s.Len(listResponse.Nodes, 0)
}

func (s *HandlerSuite) createAttestedNode(ctx context.Context, spiffeID string) {
Copy link
Member

Choose a reason for hiding this comment

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

for a helper like this, unless you really need to parameterize the context, i'd just hardcode context.Background()

// Represents an evict response
message EvictAgentResponse {
// If the entry is successfully deleted, deleteSucceed will be true
bool deleteSucceed = 1;
Copy link
Member

Choose a reason for hiding this comment

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

maybe bool evicted = 1?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As suggested below, I'll modify this API to return the deleted node


// Represents an evict request
message EvictAgentRequest {
// Core identity of the agent to be de-attested.
Copy link
Member

Choose a reason for hiding this comment

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

i'm not familiar with "core identity". is this what we are calling the true attested node SPIFFE ID (as opposed to a vanity ID)?

Copy link
Member

Choose a reason for hiding this comment

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

I may be responsible fo this :-| I used the term when trying to describe the difference between an agent's identity and a vanity ID.... frankly I think we would do well to put some more focus on what we call these thing. I dont know if vanity ID is the right thing or not... but I think Agent Identity or something like that is close to correct for the agent's SPIFFE ID

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok! will use "Agent Identity" 👍

rpc EvictAgent(EvictAgentRequest) returns (EvictAgentResponse);

// List all attested nodes
rpc ListAgents(spire.common.Empty) returns (ListAgentsResponse);
Copy link
Member

Choose a reason for hiding this comment

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

I know it there are places in the registration API that don't follow this rule, but gRPC best practices are that each request should have a distinct request and response type. I'd prefer an empty ListAgentsRequest instead of a spire.common.Empty message, since it allows us to extend it later with less fuss.

Copy link
Member

@evan2645 evan2645 left a comment

Choose a reason for hiding this comment

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

thank you very much for this @marcosy! This feature has been asked for a lot recently

I left a bunch of small little nits, but overall looking great!

}

// make sure SPIFFE ID is well formed
c.SpiffeID, err = idutil.NormalizeSpiffeID(c.SpiffeID, idutil.AllowAny())
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps we can validate this with idutil.AllowAnyTrustDomainAgent()? That will take the extra step to ensure that the specified ID is actually an agent ID


//EvictCLI command for node "de-attestation"
type EvictCLI struct {
RegistrationClient registration.RegistrationClient
Copy link
Member

Choose a reason for hiding this comment

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

Nit: should we leave this as unexported since it's only really used for testing?

}

func (EvictCLI) Synopsis() string {
return "De-attest an agent givent its spiffeID"
Copy link
Member

Choose a reason for hiding this comment

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

Nit: IMO we should be consistent with the naming, maybe something like Evict an agent given its SPIFFE ID? Also, small typo s/givent/given/

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed! Will standardize on "Evict"

if c.RegistrationClient == nil {
c.RegistrationClient, err = util.NewRegistrationClient(config.RegistrationUDSPath)
if err != nil {
fmt.Printf("Error creating registration client: %v \n", err)
Copy link
Member

Choose a reason for hiding this comment

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

Since this error will be seen by a user, it would be good to have something that is a little more "plain english" like Error establishing connection to the Registration API: %v ... My basic thought process here is "As an ordinary user trying out SPIRE, will I understand what a registration client is and will I know how to fix it"

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! 👍

}
evictResponse, err := c.RegistrationClient.EvictAgent(ctx, &registration.EvictAgentRequest{SpiffeID: config.SpiffeID})
if err != nil {
fmt.Printf("Error de-attesting agent: %v \n", err)
Copy link
Member

Choose a reason for hiding this comment

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

Similar nit here as before on consistent terms e.g. Error evicting agent: %v

Next few lines have a couple references too

}, err
}

h.Log.Infof("Successfully de-attested agent with ID: %q", spiffeID)
Copy link
Member

Choose a reason for hiding this comment

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

Same nit here

Not quite sure if this should be Infof or Debugf... kind of feels like the latter, unless we also want to start logging registration entry changes at Info level

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed! I believe this should be logged as "debug" 👍

return &registration.ListAgentsResponse{Nodes: listAttestedNodesResponse.Nodes}, nil
}

func (h *Handler) deleteAttestationEntry(ctx context.Context, baseSPIFFEID string) error {
Copy link
Member

Choose a reason for hiding this comment

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

nit: it would be nice if this matched the datastore naming convention e.g. deleteAttestedNode

Copy link
Member

Choose a reason for hiding this comment

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

Another note here, I've been trying to avoid the term baseSPIFFEID because I don't think it carries a lot of meaning and can cause confusion... it was a term we coined very early on in the design and development process, but as time goes on, I've found I prefer agentID or something along those lines

func (h *Handler) ListAgents(ctx context.Context, empty *common.Empty) (*registration.ListAgentsResponse, error) {
dataStore := h.Catalog.DataStores()[0]
listAttestedNodesRequest := &datastore.ListAttestedNodesRequest{}
listAttestedNodesResponse, err := dataStore.ListAttestedNodes(ctx, listAttestedNodesRequest)
Copy link
Member

Choose a reason for hiding this comment

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

This could be a little more succinct and easier to read if the variable names were simply req and resp... the variables are scoped to this function, the golang idiom is shorter names are better particularly if they are declared and used very close together

// Represents an evict response
message EvictAgentResponse {
// If the entry is successfully deleted, deleteSucceed will be true
bool deleteSucceed = 1;
Copy link
Member

Choose a reason for hiding this comment

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

I think we should avoid this pattern, it can be error prone because consumers may forget to check the value of deleteSucceed. Instead, if the delete has failed for some reason, we should return an error directly.

Instead of returning deleteSucceed, one option is to return spire.common.AttestedNode representing the entry we just deleted

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 point! I'll modify the API to return the deleted node


// Evict removes (de-attest) an attestation entry from the attested nodes store
rpc EvictAgent(EvictAgentRequest) returns (EvictAgentResponse);

Copy link
Member

Choose a reason for hiding this comment

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

nit: can remove this space to keep the agent-related calls together

Signed-off-by: Marcos G. Yedro <marcosyedro@gmail.com>
Signed-off-by: Marcos G. Yedro <marcosyedro@gmail.com>
Copy link
Member

@azdagron azdagron left a comment

Choose a reason for hiding this comment

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

Great! Thanks for this.

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.

Add an evict method to the registration API
3 participants