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 top level keys for policy definition into specs #3048

Merged
merged 4 commits into from
Oct 26, 2023

Conversation

michel-laterman
Copy link
Contributor

@michel-laterman michel-laterman commented Oct 19, 2023

What is the problem this PR solves?

Policy is only defined as a generic interface{} or json.RawMessage.

How does this PR solve the problem?

Define agent policy structure as part of the openapi and json schema specs.
Use the generated json schema struct when fleet-server interacts with Elasticsearch.

Future work will use the struct generated from openapi as part of responses

@michel-laterman michel-laterman added Team:Fleet Label for the Fleet team tech debt labels Oct 19, 2023
@michel-laterman michel-laterman changed the title Add top level keys for policy definition into openapi spec Add top level keys for policy definition into specs Oct 19, 2023
@@ -72,29 +72,36 @@
},
"data": {
"description": "The opaque payload.",
"type": "object",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Our custom go json schema generator has some strange behaviour

If type: object is found it will define a go struct with that name then use it as the inline type for the attribute, If format: raw is found it will define the inline type as json.RawMessage (what we want for these cases).
If both are used, it leads to an unused (empty) struct definition.

Also names/attributes can collide, so if we have a top level object named agent, and an attribute named agent (defined with type: object and format:raw), things go wrong.

I removed type: object from attributes we want as a json.RawMessage in order to avoid this behaviour in the future

"type": "string"
},

"checkin": {
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 was not scoped correctly (as defined in the draft-07 definition) so the go structs for checkin were not created.

The openapi spec for checkin requests has less strict definition, @cmacknz should we update the openapi spec to check for the checkin as it would be defined here?

model/schema.json Show resolved Hide resolved
@@ -490,7 +490,42 @@ components:
yaml: "timeout"
signed:
$ref: "#/components/schemas/actionSignature"

policyData:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

No go code has been generated for this because it is not linked as part of an action payload at the moment.

We can likely use oneOf to generate fleet-server's structs in order to be backwards compatible if that's required

@michel-laterman michel-laterman marked this pull request as ready for review October 24, 2023 21:12
@michel-laterman michel-laterman requested a review from a team as a code owner October 24, 2023 21:12
Comment on lines 753 to 755
"outputs": {
"description": "A map of all outputs that the agent running the policy can use to send data to.",
"format": "raw"
Copy link
Contributor Author

@michel-laterman michel-laterman Oct 24, 2023

Choose a reason for hiding this comment

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

@juliaElastic, If we define additional keys as part of the policy definition it should remove some of the boilerplate around casting for the remote output definition.
But we wound need to decide on how much detail we want to get into (should fleet-server care or be aware of attributes it does not use? should we use the additionalProperties to hide some of these?)

The internal policy handler always treats outputs and inputs as some form of map[string]interface{}, so at the very least we may want to change the top level keys from json.RawMessage (which is not unmarshalled) to a map or slice (for secret_references)

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 did a little expirementing and was unable to get the json schema generator tool we use to output generic objects (type map[string]interface), but it's easily able to do lists of type []interface{}, or just assign it the generic interface{} type.

That means if we want to have a stricter definition in fleet-server then a json.RawMessage or interface{} for outputs we would need to define the properties that exist in the policy in Elasticsearch (the schema we return from our openapi endpoint can differ by removing the secret_token for instance)

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it would be nice to define at least the properties that are being used in fleet-server.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Outputs is tracked as a map[string]map[string]interface{} to make it easy to iterate in the fleet-server.
I didn't define attributes in outputs as it can get complex (ssl, proxies, keys, etc may be involved)

Use the generated model.PolicyData struct for operations within the
fleet-server.
}

// Validate that default was found
if pp.Default.Name != "other" {
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'm not sure how this test was passing as the minified policy had a single output named "default"

// The role is required to do api key management
if p.Role == nil {
zlog.Error().
Msg("policy does not contain required output permission section")
return ErrNoOutputPerms
}
if _, ok := outputMap[p.Name]; !ok {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

fail fast here instead of a possible panic on line 245


r := policy.RevisionFromPolicy(pp.Policy)
// FIXME use better action definition from open api spec
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 will be a part of the pr to define actions/acks (when we use the policyData defined as part of the openapi spec)

// findDefaultName returns the name of the 1st output with the "elasticsearch" type or falls back to behaviour that relies on deprecated fields.
//
// Previous fleet-server and elastic-agent released had a default output which was removed Sept 2021.
func findDefaultOutputName(outputs map[string]map[string]interface{}) (string, 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.

From what I can tell ParsedPolicy.Default is only set in the fleet-server, nothing fleet-server runs uses it (and it's not transmitted as part of a policy_change action. Do we still want to keep this?
@blakerouse I believe you wrote this, do you remember any additional context?

Copy link
Contributor

@juliaElastic juliaElastic left a comment

Choose a reason for hiding this comment

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

LGTM

@elastic-sonarqube
Copy link

Copy link
Member

@kpollich kpollich left a comment

Choose a reason for hiding this comment

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

Code LGTM - thanks for taking this on.

@michel-laterman michel-laterman merged commit 0831837 into elastic:main Oct 26, 2023
@michel-laterman michel-laterman deleted the oapi-policy-def branch October 26, 2023 19:11
return err
}

outputMap[p.Name]["api_key"] = output.APIKey
Copy link
Member

@nchaulet nchaulet Oct 28, 2023

Choose a reason for hiding this comment

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

@michel-laterman it seems to me it is going to mutate the parsedPolicy output here and potentially impact concurrent checkin no? think previously we where parsing the fields for each checkin and mutating the parsed data

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Team:Fleet Label for the Fleet team tech debt
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants