Skip to content
This repository was archived by the owner on Feb 23, 2019. It is now read-only.

Conversation

djmitche
Copy link
Contributor

You might want to take this commit-by-commit.

Mostly I'd like some thought and feedback on the security implications. The risk is that someone makes a try job with the retrigger action configured to run hook project-gecko/in-tree-action-3-relpromo with a payload that promotes some malicious try build as Firefox 666. Then some innocent test task turns orange on the try job and they kindly ask someone in releng or relman to click "retrigger" for that task.

My thinking is that a "generic" actions UI would run the user through two dialogs for an hook action:

  • Enter the task input so that it matches the schema
  • See and confirm the hookId, hookGroupId, and rendered payload
    The first can be skipped if there's no schema, of course.

Treeherder, however, can do a bit better:

  • Use authorizedScopes=['mozilla-group:scm_level_1'] for try, 2 for level-2 repos, etc.
  • For hard-wired things like 'r', check the hookGroupId/hookId
  • Do the two-phase confirmation for everything else.

This moves some of the more verbose schema descriptions out into the
manual, leaving the schema quite a bit shorter.  It will get longer when
a new kind is added!
@djmitche djmitche self-assigned this Apr 12, 2018
Copy link
Contributor

@jonasfj jonasfj left a comment

Choose a reason for hiding this comment

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

Over all I LOVE this!!!

Most of my comments are suggestions, but refactoring the schema is probably a good idea.

- task
- type: object
properties:
kind: hook
Copy link
Contributor

Choose a reason for hiding this comment

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

this doesn't work

items:
type: object
additionalProperties:
allOf:
Copy link
Contributor

Choose a reason for hiding this comment

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

I propose refactoring the schema into:

oneOf:
  - type: object
    properties:
      kind: {enum: task}
    ...
  - type: object
    properties:
      kind: {enum: hook}
    ...

even the two kinds share some properties, just duplicate those properties. It's okay to document them twice.
The allOf + anyOf refactoring is harder to do in your head.

Copy link
Contributor

Choose a reason for hiding this comment

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

Another way to reference definitions with $ref, this is okay if we render it using a viewer...

Putting definitions to be referenced under a top-level property definitions: {"mydef": ....} is convention in json schemas. Then reference it with $ref: '#/definitions/mydef'

decision task couldn't do.

Instead, the user interface should require the user to confirm each action,
displaying the hookGroupId, hookId, and hookPayload.
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add something like:

Furthermore, hook implementation should be designed to guard against malicious input,
which could be triggered by phishing an unsuspecting administrator to trigger a hook action
from a low privileged task with bad intend, causing an evil hookPayload.


* it can limit the scopes available using
[authorizedScopes](https://docs.taskcluster.net/manual/design/apis/hawk/authorized-scopes)
based on some other definiitve information about the task -- for example,
Copy link
Contributor

Choose a reason for hiding this comment

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

*definiitve


The "task" kind requires that the user invoking the task has all of the scopes
necessary to run the action task (and to create any further tasks). Such scopes
might allow a user to perform undesirable actions with the Taskcluster API.
Copy link
Contributor

Choose a reason for hiding this comment

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

Granting such scopes allow a user to perform undesirable actions with the Taskcluster API

`hook-id:<hookGroupId>/<hookId>`. The method also verifies its payload against
the hook's `triggerSchema`. This allows a controlled privilege escalation:
only clients with the appropriate `trigger-hook` scope may trigger a hook, and
only if they provide a payload matching the schema. If both of those conditions
Copy link
Contributor

Choose a reason for hiding this comment

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

only if they provide a payload matching the schema

^ this is not a security assertion, as the attacker controls the schema in actions.json

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe rephrase this section... I love the sentence "This allows a controlled privilege escalation".

But I'm a little confused about the rest. As an action designer, using a hook means I can grant the user more restricted scopes. And I can use the hook to create a controlled privileged escalation, where my hook implementation sanitizes untrusted input.

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 meant matching triggerSchema, which the attacker does not control. What is the confusion?

Copy link
Contributor

Choose a reason for hiding this comment

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

Okay, this is the triggerSchema in hooks.. I didn't see that got added.

Curious, will that validate input from both HTTP triggers and pulse triggers...

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, triggerSchema only applies to triggers. I think we decided to add an additional pulseMessageSchema, but I don't recall. Anyway, that part (pulse) isn't implemented yet.

JSON-e rendering performed by the hooks service. Do not confuse the two
operations!

### Choosing a Kind
Copy link
Contributor

Choose a reason for hiding this comment

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

Some of this belong more in action design guidelines than the action specification.

This is a nit, but it would be nice to corner these discussion topics and examples into a separate document.
But I'm okay with this here too :)

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 move it to a guidelines.md..


Once the hook is complete and functional, only then should you design the
`actions.json` entry to trigger it. An "hook" action is just a template for how
to call `hooks.triggerHook` and does not offer any level of security.
Copy link
Contributor

Choose a reason for hiding this comment

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

At this point you should remember that the schema is only for documentation, and you can rely on the integrity of actions.json for security.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

cannot?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, cannot rely on...

are met, then the resulting task may execute with permissions the originating
client does not posses.

To design a hook-based action, start with the hook and consider the minimal
Copy link
Contributor

Choose a reason for hiding this comment

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

Could this be prefixed **Example, ** (in markdown)

That way it's easy to see that I don't care :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's not an example, though..

Copy link
Contributor

Choose a reason for hiding this comment

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

Could it have an informal title or something...

### "hook" Actions

Hook actions have no such luxury, as they are intended to do things the
decision task couldn't do.
Copy link
Contributor

Choose a reason for hiding this comment

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

We could add that UIs triggering hook actions should validate that the decision task posses the scope:

  • decision-task:reference-hook-action:<hookGroupId>/<hookId>

Obviously, the UI would have to call auth.expandScope(decisionTask.scopes) to determine the scopes.

This would protect against the case where a try-decision task is tweaked to add an action that triggers the hook to release firefox. As scm_level_1 doesn't have permission to reference said action.

@djmitche, @imbstack, maybe think this over ^, I'll admit my initial thought is that this is too complicated. That this is something we'll get wrong every time we add a new hook action. On the hand scope errors like this should be easy to make visible and understand.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hm, I like that idea. It does sound like a good bit of work to implement, but not too bad..

Copy link
Contributor

Choose a reason for hiding this comment

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

It is probably worth looking at what the releng scriptworkers are doing. @escapewindow might have some thoughts on this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is probably worth looking at what the releng scriptworkers are doing. @escapewindow might have some thoughts on this.

That's a bit of a different situation -- recognizing a "legitimate" decision task for Firefox. The spec here is more general, and could apply to any project, Firefox or not, with any kind of decision task.


Variables
---------
In practice it's encourage that consumers employ a facility that can generate
Copy link
Contributor

Choose a reason for hiding this comment

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

encouraged

relevant. Thus, what context the action should be presented to the
end-user.
schema:
$ref: http://json-schema.org/schema
Copy link
Contributor

Choose a reason for hiding this comment

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

Will this be a valid external reference for things that don't fetch external 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 don't know - I didn't change this part. This schema file is just to make Jonas happy anyway, and isn't machine-interpreted..

decision task couldn't do.

Instead, the user interface should require the user to confirm each action,
displaying the hookGroupId, hookId, and hookPayload.
Copy link
Contributor

Choose a reason for hiding this comment

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

Not that we necessarily need to do this now, but I wonder if we could make this even more solid. Very poorly thought out ideas:

  • require linking to that hook in the tools site?
  • suggest displaying a "you have run this hook N times before" the way browsers do with ssl/website stuff
  • none of the above!

Copy link
Contributor

Choose a reason for hiding this comment

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

Uh, maybe require the UI display the name, description and owner properties of the hook.

That way a warning can be added to the description property indicating that the hook could do something bad... Stuff like that would smart..

@djmitche
Copy link
Contributor Author

I really like the decision-task-scopes thing, but I'm hesitant to introduce a new top-level scope name (decision-task:..). I see that giving the decision task hooks:trigger-hook:.. would be bad (as we do not want a rogue L3 push to be able to start a release, for example). The solution is very similar to that for kind=task.

I can overcome my hesitation if necessary..

@jonasfj
Copy link
Contributor

jonasfj commented Apr 16, 2018

@djmitche, yeah, I don't like making a lot of new top-level scopes either...
Could we make some that are repo specific... or is this a scope that's like treeherder:... or something...

Maybe the top-level scope is related to actions.... The idea that there is a top-level scope that a task will need in-order to expose actions isn't crazy. But let's talk about how to mitigate phishing on vidyo or something.

- task
- type: object
properties:
kind: {enum: hook}
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 to be kind: {enum: ['hook']}

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 trusted #250 (comment) :)

anyOf:
- type: object
properties:
kind: {enum: task}
Copy link
Contributor

Choose a reason for hiding this comment

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

this should be {enum: ['task']}

@djmitche
Copy link
Contributor Author

We settled on scope in-tree:hook-action:<hookGroupId>/<hookId>.

Note that there's no reason to allow the user to work around this in the UI. If you want to test a hook, just call hooks.triggerHook yourself.

@djmitche djmitche merged commit b4b6d0e into taskcluster:master Apr 18, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants