-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
feat: Add mode to require Workflows to use workflowTemplateRef #3149
Conversation
cmd/workflow-controller/main.go
Outdated
@@ -44,6 +44,7 @@ func NewRootCommand() *cobra.Command { | |||
qps float32 | |||
namespaced bool // --namespaced | |||
managedNamespace string // --managed-namespace | |||
referenceMode bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Name is not final yet.. still thinking of better options
workflow/controller/operator.go
Outdated
} else if woc.controller.referenceMode { | ||
// If the controller is in reference mode, ensure that the stored spec is identical to the reference spec at every operation | ||
wftSpec, err := woc.fetchWorkflowSpec() | ||
if err != nil { | ||
return nil, wfv1.Arguments{}, err | ||
} | ||
if woc.wf.Status.StoredWorkflowSpec.String() != wftSpec.String() { | ||
return nil, wfv1.Arguments{}, fmt.Errorf("workflowTemplateRef reference may not change during execution when the controller is in reference mode") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Notably, we need to check that the WorkflowTemplate and our own StoredWorkflowSpec have not changed. We do this to prevent attackers from specifying arbitrary code in wf.Status.StoredWorkflowSpec
and simply running it by using workflowTemplateRef
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the can change the status, surely they could have changed the spec?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, but the key is that you can only change the workflowTemplateRef
to another (already existing) WorkflowTemplate
. The idea with this feature is to not allow an arbitrary WorkflowSpec
from being executed, but instead restricting them to an already present WorkflowTemplate
Kudos, SonarCloud Quality Gate passed!
|
Could we better enforce this when you submit a workflow? |
I think this would make the feature easy to circumvent if the user has |
I think as a user I would want to know that my workflow is invalid - because I've used inline templates - I'd like to know that sooner rather than later - rejected at submission. I'm assuming we lint the workflow before we execute it (as a result of |
Since the restriction is enabled in the controller, we won't know if the controller will reject a Workflow before it is submitted. We could add an endpoint for the controller to tell us if it's in reference mode. The CLI/API would then query the endpoint when doing client-side validation and act appropriately. However, I think this might be unnecessary since this logic is implemented at the beginning of the operation logic, meaning that a Workflow will fail immediately with a message displayed with the cause:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, only one suggestion
workflow/controller/operator.go
Outdated
} | ||
|
||
func (woc *wfOperationCtx) loadExecutionSpec() (wfv1.TemplateReferenceHolder, wfv1.Arguments, error) { | ||
|
||
executionParameters := woc.wf.Spec.Arguments | ||
|
||
if woc.wf.Spec.WorkflowTemplateRef == nil { | ||
tmplRef := &wfv1.WorkflowStep{Template: woc.wfSpec.Entrypoint} | ||
if woc.controller.Config.WorkflowRequirements.MustUseReference() { | ||
return nil, wfv1.Arguments{}, fmt.Errorf("workflows must use workflowTemplateRef to be executed when the controller is in reference mode") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can return the executionParameters
arguments instead of returning new empty structs
workflow/controller/operator.go
Outdated
return nil, wfv1.Arguments{}, err | ||
} | ||
if woc.wf.Status.StoredWorkflowSpec.String() != wftSpec.String() { | ||
return nil, wfv1.Arguments{}, fmt.Errorf("workflowTemplateRef reference may not change during execution when the controller is in reference mode") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here too for arguments
config/config.go
Outdated
|
||
type WorkflowRequirements struct { | ||
ReferenceOnly bool `json:"referenceOnly"` | ||
StrictReferenceOnly bool `json:"strictReferenceOnly"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about {reference: {strict:true}}
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jessesuen and I settled on:
data:
workflowRestrictions:
templateReferencing: Strict
Closes #2867
Currently called "reference mode" and enabled as a flag to the
workflow-controller
binary.