diff --git a/docs/fields.md b/docs/fields.md index 85999b50bf75..4a1210133ea9 100644 --- a/docs/fields.md +++ b/docs/fields.md @@ -341,6 +341,8 @@ Workflow is the definition of a workflow resource - [`title-and-description-with-markdown.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/title-and-description-with-markdown.yaml) +- [`rejected-workflow.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/validating-admission-policies/rejected-workflow.yaml) + - [`volumes-emptydir.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/volumes-emptydir.yaml) - [`volumes-existing.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/volumes-existing.yaml) @@ -799,6 +801,8 @@ WorkflowSpec is the specification of a Workflow. - [`title-and-description-with-markdown.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/title-and-description-with-markdown.yaml) +- [`rejected-workflow.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/validating-admission-policies/rejected-workflow.yaml) + - [`volumes-emptydir.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/volumes-emptydir.yaml) - [`volumes-existing.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/volumes-existing.yaml) @@ -1252,6 +1256,8 @@ CronWorkflowSpec is the specification of a CronWorkflow - [`title-and-description-with-markdown.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/title-and-description-with-markdown.yaml) +- [`rejected-workflow.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/validating-admission-policies/rejected-workflow.yaml) + - [`volumes-emptydir.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/volumes-emptydir.yaml) - [`volumes-existing.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/volumes-existing.yaml) @@ -1500,6 +1506,8 @@ Arguments to a template - [`synchronization-mutex-tmpl-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level.yaml) +- [`rejected-workflow.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/validating-admission-policies/rejected-workflow.yaml) + - [`work-avoidance.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/work-avoidance.yaml) - [`event-consumer-workfloweventbinding.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/workflow-event-binding/event-consumer-workfloweventbinding.yaml) @@ -2348,6 +2356,8 @@ Parameter indicate a passed string parameter to a service template with an optio - [`synchronization-mutex-tmpl-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level.yaml) +- [`rejected-workflow.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/validating-admission-policies/rejected-workflow.yaml) + - [`work-avoidance.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/work-avoidance.yaml) - [`event-consumer-workfloweventbinding.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/workflow-event-binding/event-consumer-workfloweventbinding.yaml) @@ -3043,6 +3053,8 @@ ScriptTemplate is a template subtype to enable scripting through code steps - [`scripts-python.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/scripts-python.yaml) +- [`rejected-workflow.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/validating-admission-policies/rejected-workflow.yaml) + - [`withsequence-nested-result.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/withsequence-nested-result.yaml) - [`work-avoidance.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/work-avoidance.yaml) @@ -3837,6 +3849,8 @@ MetricLabel is a single label for a prometheus metric - [`steps-inline-workflow.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/steps-inline-workflow.yaml) - [`title-and-description-with-markdown.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/title-and-description-with-markdown.yaml) + +- [`rejected-workflow.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/validating-admission-policies/rejected-workflow.yaml) ### Fields @@ -4095,6 +4109,8 @@ DataSource sources external data into a data template - [`scripts-python.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/scripts-python.yaml) +- [`rejected-workflow.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/validating-admission-policies/rejected-workflow.yaml) + - [`withsequence-nested-result.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/withsequence-nested-result.yaml) - [`work-avoidance.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/work-avoidance.yaml) @@ -5025,6 +5041,8 @@ ObjectMeta is metadata that all persisted resources must have, which includes al - [`title-and-description-with-markdown.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/title-and-description-with-markdown.yaml) +- [`rejected-workflow.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/validating-admission-policies/rejected-workflow.yaml) + - [`volumes-emptydir.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/volumes-emptydir.yaml) - [`volumes-existing.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/volumes-existing.yaml) @@ -5623,6 +5641,8 @@ A single application container that you want to run within a pod. - [`title-and-description-with-markdown.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/title-and-description-with-markdown.yaml) +- [`rejected-workflow.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/validating-admission-policies/rejected-workflow.yaml) + - [`volumes-emptydir.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/volumes-emptydir.yaml) - [`volumes-existing.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/volumes-existing.yaml) @@ -6619,6 +6639,8 @@ ImageVolumeSource represents a image volume resource. - [`title-and-description-with-markdown.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/title-and-description-with-markdown.yaml) +- [`rejected-workflow.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/validating-admission-policies/rejected-workflow.yaml) + - [`volumes-emptydir.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/volumes-emptydir.yaml) - [`volumes-existing.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/volumes-existing.yaml) diff --git a/examples/validating-admission-policies/argo-dangerous-interpolation-vap-binding.yaml b/examples/validating-admission-policies/argo-dangerous-interpolation-vap-binding.yaml new file mode 100644 index 000000000000..6a83a4ba1c55 --- /dev/null +++ b/examples/validating-admission-policies/argo-dangerous-interpolation-vap-binding.yaml @@ -0,0 +1,15 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicyBinding +metadata: + name: "argo-dangerous-interpolation-vap-binding" +spec: + policyName: "argo-dangerous-interpolation-vap" + # Reject workflows that match the VAP. + # You could also set this to "Audit" to instead generate an audit event on a + # match, which can be used to identify workflows that need to be fixed. + validationActions: [Deny] + matchResources: + objectSelector: + matchLabels: + # Only match workflows with the "workflows.argoproj.io/vap" label. + workflows.argoproj.io/vap: "true" \ No newline at end of file diff --git a/examples/validating-admission-policies/argo-dangerous-interpolation-vap.yaml b/examples/validating-admission-policies/argo-dangerous-interpolation-vap.yaml new file mode 100644 index 000000000000..8c5e3133e16c --- /dev/null +++ b/examples/validating-admission-policies/argo-dangerous-interpolation-vap.yaml @@ -0,0 +1,43 @@ +# This admission policy (https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/) +# can be used to block workflows that use string interpolation inside the fields "command", +# "args", or "source". +# +# Interpolating untrusted user input into this fields can lead to command +# injection vulnerabilities (https://owasp.org/www-community/attacks/Command_Injection). +# +# This policy will only work when using the full CRDs (https://argo-workflows.readthedocs.io/en/latest/installation/#full-crds). +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingAdmissionPolicy +metadata: + name: "argo-dangerous-interpolation-vap" +spec: + failurePolicy: Fail + matchConstraints: + resourceRules: + - apiGroups: ["argoproj.io"] + apiVersions: ["v1alpha1"] + operations: ["CREATE", "UPDATE"] + resources: ["workflows"] + validations: + - expression: | + !object.spec.templates.exists(template, + // Aggregate all command/args/source fields for all containers into a 2D array, + // since CEL doesn't support array flattening. + // For "container" and "script" templates, there's only one container, + // so the first array will have a single entry. + // For "containerSet" templates, the first array could have many entries. + ( + [ template.?container.command.orValue([]) + + template.?container.args.orValue([]) + + template.?script.command.orValue([]) + + [template.?script.source.orValue("")] + ] + template.?containerSet.optMap(containerSet, + containerSet.containers.map(c, + c.?command.orValue([]) + c.?args.orValue([]) + ) + ).orValue([]) + ).exists(containerValues, + containerValues.exists(value, value.matches('\\{\\{[^\\}]*\\}\\}')) + ) + ) + message: "Dangerous interpolation detected" \ No newline at end of file diff --git a/examples/validating-admission-policies/rejected-workflow.yaml b/examples/validating-admission-policies/rejected-workflow.yaml new file mode 100644 index 000000000000..4ec0e6693671 --- /dev/null +++ b/examples/validating-admission-policies/rejected-workflow.yaml @@ -0,0 +1,31 @@ +# This workflow contains a "container" template and "script" template that both +# match the validating admission policy at +# examples/validating-admission-policies/argo-dangerous-interpolation-vap.yaml. +# +# Attempting to submit it should give you the following: +# $ kubectl create -f examples/validating-admission-policies/rejected-workflow.yaml +# The workflows "rejected-workflow-fvj4h" is invalid: : ValidatingAdmissionPolicy 'argo-dangerous-interpolation-vap' with binding 'argo-dangerous-interpolation-vap-binding' denied request: Dangerous interpolation detected +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: rejected-workflow- + labels: + workflows.argoproj.io/vap: "true" +spec: + entrypoint: container-with-interpolation + arguments: + parameters: + - name: message + value: test + templates: + - name: container-with-interpolation + container: + image: argoproj/argosay:v2 + args: + - echo + - "{{workflow.parameters.message}}" + - name: script-with-interpolation + script: + image: argoproj/argosay:v2 + command: [sh, -c] + source: "{{workflow.parameters.message}}" \ No newline at end of file