Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
46d5763
Add new page
OliviaShoup Jul 22, 2025
799bacb
Merge branch 'master' into olivia.shoup/docs-11282
OliviaShoup Aug 18, 2025
229ba7d
Add first draft
OliviaShoup Aug 20, 2025
9180a2c
Update content/en/actions/private_actions/run_script.md
OliviaShoup Aug 28, 2025
ba333cc
Cut mention of other integrations
OliviaShoup Aug 28, 2025
8eccba4
Merge branch 'olivia.shoup/docs-11282' of github.com:DataDog/document…
OliviaShoup Aug 28, 2025
6af09ee
Update content/en/actions/private_actions/run_script.md
OliviaShoup Aug 28, 2025
ef1e22c
Cut redundant info in pre-requisites
OliviaShoup Aug 28, 2025
5ec9395
Merge branch 'olivia.shoup/docs-11282' of github.com:DataDog/document…
OliviaShoup Aug 28, 2025
d0574cf
Cut bit about placeholder
OliviaShoup Aug 28, 2025
4dedb25
Cut Manage Access section
OliviaShoup Aug 28, 2025
a4939b8
Cut Docker configuration example (for now)
OliviaShoup Aug 28, 2025
6e00135
Update content/en/actions/private_actions/run_script.md
OliviaShoup Aug 28, 2025
457305f
Cut Helm deployment info
OliviaShoup Aug 28, 2025
e271f7c
Merge branch 'olivia.shoup/docs-11282' of github.com:DataDog/document…
OliviaShoup Aug 28, 2025
cafbbb6
Update content/en/actions/private_actions/run_script.md
OliviaShoup Aug 28, 2025
a58396f
Update content/en/actions/private_actions/run_script.md
OliviaShoup Aug 28, 2025
f81bde3
Update content/en/actions/private_actions/run_script.md
OliviaShoup Aug 28, 2025
dc5177b
Merge branch 'master' into olivia.shoup/docs-11282
OliviaShoup Aug 28, 2025
299fbbd
Add section for upgrading the PAR
OliviaShoup Aug 28, 2025
8b9ff23
Cut outdated info
OliviaShoup Sep 2, 2025
2eec43e
Update Docker Compose YAML
OliviaShoup Sep 2, 2025
1430fc2
Rename `runner` in YAML
OliviaShoup Sep 2, 2025
4e121e0
Add YAML tag to code block
OliviaShoup Sep 2, 2025
0772796
Make private action runner lowercase
OliviaShoup Sep 2, 2025
43c8754
Update heading with abbreviation
OliviaShoup Sep 2, 2025
4b5a90a
Fix heading tense
OliviaShoup Sep 3, 2025
1510ad1
Reword + add link to Run Predefined Script in app
OliviaShoup Sep 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion config/_default/menus/main.en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2852,11 +2852,16 @@ menu:
parent: private_actions
identifier: use_private_actions
weight: 201
- name: Run a Script
url: actions/private_actions/run_script/
parent: private_actions
identifier: run_script
weight: 202
- name: Private Action Credentials
url: actions/private_actions/private_action_credentials/
parent: private_actions
identifier: private_actions_creds
weight: 202
weight: 203
- name: Cloudcraft
url: datadog_cloudcraft/
pre: cloudcraft
Expand Down
3 changes: 3 additions & 0 deletions content/en/actions/private_actions/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ further_reading:
- link: "actions/private_actions/use_private_actions"
tag: "Documentation"
text: "Use Private Actions"
- link: "actions/private_actions/run_script"
tag: "Documentation"
text: "Run a Script with the Private Action Runner"
- link: "actions/private_actions/private_action_credentials"
tag: "Documentation"
text: "Handling Private Action Credentials"
Expand Down
239 changes: 239 additions & 0 deletions content/en/actions/private_actions/run_script.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
---
title: Run a Script with the Private Action Runner
disable_toc: false
aliases:
- service_management/workflows/private_actions/run_script
- service_management/app_builder/private_actions/run_script
---

## Overview

The private action runner (PAR) script action allows you to run custom scripts and Linux binaries within your Datadog workflows and apps. Unlike standard private actions that call specific APIs or services, the script action gives you the flexibility to execute arbitrary commands, shell scripts, and command-line tools directly from the private action runner in your private network.

<div class="alert alert-warning">
<strong>Security Notice:</strong> The PAR script action runs within a containerized environment using a dedicated Linux user named `scriptuser` for enhanced security. Datadog enforces container sandboxing and only accepts signed tasks, but you decide which binaries and scripts are allowed. Always review every command you add to the script action allow-list, especially ones that take dynamic user input. Ensure that your actions are configured with the least privileged commands, and carefully review the permissions you share through connections. For more information, see <a href="/actions/connections/?tab=workflowautomation#connection-security-considerations">connection security considerations</a>.
</div>

## Use cases

The following table outlines supported and unsupported use cases for the script action:

| Use Case | Supported | Notes |
|-----------------------------------------------------|-----------|------------------------------------------------------------------------------------------------------------------------------|
| Running Linux binaries (`ls`, `rm`, `find`, `curl`) | Yes | In order to run native Linux binaries, the relevant files must be accessible to the container. |
| Running CLIs (`aws`, `terraform`, `kubectl`) | Yes | The CLI and your CLI credentials must be added to your custom image. |
| Running scripts (`bash`, `python`) | Yes | Scripts can be mounted inside the container. Interpreters such as Python must be installed on your custom image. |
| Running privileged commands (`systemctl restart`) | No | Because the PAR runs inside a container, it does not have high privilege permissions on the host. |
| Windows tools (PowerShell) | No | Because the PAR runs inside a Linux container, native Windows tools are not supported. |

## Prerequisites

To use the script action, you need:

- **Custom tools**: For CLI tools not included in the base image, you need to create a custom Docker image.
- **PAR Version**: 1.7.0 or later. See [set up a private action runner][2] to get started.
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this dynamic ? The version is 1.7.0 but we bump it regularly

- anything else? 🤨

## Set up a PAR script

### 1. Update your runner image

Replace the standard PAR image with the development image that supports script actions. The development images are published on [Docker Hub][2].

**Standard image:**
```
gcr.io/datadoghq/private-action-runner:v1.3.0
```

**Script-enabled image:**
```
datadog/private-action-runner-dev:latest@sha256:4e990e496b79d02514c19a633042d27be1ba8e7a4b9018efd0e942ed1a070ad8
```

You can either reuse an existing runner's identity by changing the image, or create a brand new runner.
Comment on lines +39 to +53
Copy link
Contributor

Choose a reason for hiding this comment

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

These are specific to the preview phase PAR Version**: 1.7.0 or later should be sufficient


### 2. Create a script connection

1. Navigate to the **Private Action Runner** page in [Workflow Automation][4] or [App Builder][5].
1. Create a new script connection and associate it with your private action runner.
1. Select this connection when using the script action in your workflows or apps.
Comment on lines +57 to +59
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 we can add a screenshot there ?
image


### 3. Configure the action catalog

Navigate to the Action Catalog and select [**Run Predefined Script**][10]. This action is available for use in both workflows and apps.

## Configuration

Configure script actions through your runner's `config.yaml` file. If you create a new runner and select the script bundle, you get a default configuration.

### Basic configuration

```yaml
# Add the script action to the allowlist
actionsAllowlist:
- com.datadoghq.script.runPredefinedScript

# Configure different scripts
bundles:
"com.datadoghq.script":
runPredefinedScript:
echo:
command: ["echo", "Hello world"]
# Use workflow-like syntax to retrieve values from parameters
echo-parametrized:
command: ["echo", "{{ parameters.echoValue }}"]
echo-nested-parametrized:
command: ["echo", "{{ parameters.nested.echoValue }}"]
```
Comment on lines +67 to +87
Copy link
Contributor

Choose a reason for hiding this comment

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

the scripts are now in the script connection file (which should be in credentials/script.yaml by default)

So maybe something like
======================>

Configure script actions through your runner's config.yaml file and the script connection (credentials/script.yaml by default). If you create a new runner and select the script bundle, you get a default configuration.

Basic configuration

# Add the script action to the allowlist (`config.yaml`)
actionsAllowlist:
  - com.datadoghq.script.runPredefinedScript
# Configure your script connection (`credentials/script.yaml`)
schemaId: script-credentials-v1
runPredefinedScript:
  # use "echo" as the "Script name" in the action configuration
  echo:
    # use an array to specify the command
    command: ["echo", "Hello world"]

  # another script
  echo-parametrized:
    # you can use workflow syntax (https://docs.datadoghq.com/actions/workflows/variables/) to retrieve values from the parameters object
    command: [ "echo", "{{ parameters.echoValue }}" ]
    # you can use json schema (https://json-schema.org/) to validate the parameters
    parameterSchema:
      properties:
        echoValue:
          type: string
          const: "world"
      required:
        - echoValue


### Using the configured scripts

In your workflow or app, configure the action to use the `runPredefinedScript` with the script name you defined (for example, `echo` or `echo-parametrized`).

**Note**: There are two levels of variable resolution: one at the workflow level and one at the action level inside the runner.
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe we need a screenshot there or change the note


## Advanced usage with custom images

For binaries not available in the base runner image, create a custom image:

```dockerfile
# Dockerfile example
FROM gcr.io/datadoghq/private-action-runner:v1.7.0
RUN apt update && apt install -y python3
Comment on lines +101 to +102
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
FROM gcr.io/datadoghq/private-action-runner:v1.7.0
RUN apt update && apt install -y python3
FROM gcr.io/datadoghq/private-action-runner:v1.7.0
USER root
RUN apt update && apt install -y python3
USER dog

Copy link
Contributor

Choose a reason for hiding this comment

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

I thought end user is scriptuser ?

Copy link
Contributor

Choose a reason for hiding this comment

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

this is the default user the runner will be running as

root -> install dependencies
dog -> runs the runner (read + write permission on the runner config)
scriptuser -> the runner sus as scriptuser (no permissions on the runner config)

```

You can mount complex scripts inside the runner:

```yaml
# docker-compose example
services:
runner:
image: gcr.io/datadoghq/private-action-runner:v1.7.0
volumes:
- "./config:/etc/dd-action-runner/config"
- "./scripts:/etc/dd-action-runner-script/scripts:ro"
```

```yaml
# credentials/script.yaml
schemaId: script-credentials-v1
runPredefinedScript:
python:
command: ["python3", "/etc/dd-action-runner-script/scripts/script.py"]
shell:
command: [ "bash", "/etc/dd-action-runner-script/scripts/script.sh" ]
```

## Update the PAR

<!-- ADD INFO? -->

To view the latest version of the PAR, check [this URL][6].
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible that we display the latest version in the doc dynamically by fetching the response of this URL ?


### Docker mode
Navigate to the directory where you started the PAR. Next, navigate to the `config` directory, then the `config.yaml` file.


Find the current ID of your container:
```bash
docker ps
```

Stop the container:
```bash
docker stop <id>
```

Start a new container with [the latest image][6]. Environment variables are no longer needed. Everything is configured in the `config/config.yaml` file.

Run:
```bash
docker run -d -u 0 --platform=linux/x86_64 -p 9016:9016 -v ./config:/etc/dd-action-runner --health-cmd "curl http://localhost:9016/liveness" --health-interval 10s --health-timeout 10s --health-retries 3 gcr.io/datadoghq/private-action-runner:v1.0.0
Copy link
Contributor

Choose a reason for hiding this comment

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

I am not sure we need the flag -u 0 as it would run as root. cc @dd-gplassard

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, in the command, is it possible to have the latest image displayed ? Right now it is 1.7.0 so the command would look like

docker run -d --platform=linux/x86_64 \
  -p 9016:9016 \
  -v ./config:/etc/dd-action-runner \
  --health-cmd "curl http://localhost:9016/liveness" \
  --health-interval 10s \
  --health-timeout 10s \
  --health-retries 3 \
  gcr.io/datadoghq/private-action-runner:v1.7.0

If we can't fetch the latest image, we should replace gcr.io/datadoghq/private-action-runner:v1.7.0 by <LATEST_IMAGE> and tell users they need to replace <LATEST_IMAGE> by the response they get from https://api.datadoghq.com/api/v2/on-prem-management-service/runner/latest-image

Copy link
Contributor

@dd-gplassard dd-gplassard Sep 2, 2025

Choose a reason for hiding this comment

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

yes we recently updated the flag so we should no longer use --platform and --user (and added --cpus and --memory) maybe we should put the exact command inside the app on the runner's edit page ? This way we can keep them in sync more easily ? But maybe we can start with the doc like this for now

The latest command should be

docker run -d \
 --cpus="0.25" \
 --memory="1g"  \
 -e DD_PRIVATE_RUNNER_CONFIG_DIR=/etc/dd-action-runner/config 
 -v ./config:/etc/dd-action-runner/config \
 --health-cmd "curl http://localhost:9016/liveness" \
 --health-interval 10s \
 --health-timeout 10s \
 --health-retries 3 gcr.io/datadoghq/private-action-runner:v1.7.0

(essentially what this displays but removing all env variables except the config dir one )

```

After confirming the new PAR version is working as expected, remove the old version:
```bash
docker rm <id>
```

To check the PAR logs:
```bash
docker logs <id-of-container>
Copy link
Contributor

Choose a reason for hiding this comment

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

@dd-gplassard do you think it's better in the example to create the containers with --name datadog-private-actions-runner and then use that name downstream instead of <id-of-container> ?

Copy link
Contributor

Choose a reason for hiding this comment

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

Unfortunately I think this would be annoying because it would create conflicts when trying to rerun the command
image

```

### Docker compose mode
Navigate to the directory containing your `docker-compose.yaml` file. Next, navigate to the `config` directory, then the `config.yaml` file. Update the `image` property of the PAR and point to the latest version:

```yaml
services:
private-actions-runner:
image: gcr.io/datadoghq/private-action-runner:<latest_version>
cpus: 25
mem_limit: 1g
deploy:
replicas: 1
environment:
- DD_BASE_URL=https://app.datadoghq.com
- DD_PRIVATE_RUNNER_CONFIG_DIR=/etc/dd-action-runner/config
- RUNNER_ENROLLMENT_TOKEN=<the_token>
- STATSD_ENABLED=true
volumes:
- "./config:/etc/dd-action-runner/config"

Start the container again:
```bash
docker compose up -d
```

To check the logs:
```bash
docker compose logs runner
```

### Helm mode
When using Helm, there are two options for upgrading the PAR:
1. **(Recommended)** Upgrade the chart, which will use the latest version of the PAR. There may be changes to the chart; please review [our changelog][8].
1. Upgrade the runner without upgrading the chart.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
1. Upgrade the runner without upgrading the chart.
2. Upgrade the runner without upgrading the chart.


#### Upgrading the chart (recommended)

Navigate to the directory containing your `values.yaml` file and run:

```bash
helm repo update
helm upgrade <RELEASE_NAME> datadog/private-action-runner -f ./values.yaml
Copy link
Contributor

Choose a reason for hiding this comment

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

we should say <RELEASE_NAME> is the release name they used when creating the runner. But I believe here it will make it easier if this Upgrade section is closed to the Create section so users keep stay in the same context.

```

#### Upgrading the PAR only

Specify the PAR version in your `values.yaml` under the `common.image.tag` key with the values found [here][9]:

```yaml
common:
image:
repository: gcr.io/datadoghq/private-action-runner # optional
# latest image https://api.datadoghq.com/api/v2/on-prem-management-service/runner/latest-image
tag: v1.0.0
```

Then run:
```bash
helm upgrade <RELEASE_NAME> datadog/private-action-runner -f ./values.yaml
```

To check the logs:
```bash
kubectl get pods
kubectl logs <name-of-the-pod>
```

[1]: /actions/private_actions/use_private_actions/?tab=docker#supported-private-actions
[2]: /actions/private_actions/use_private_actions/#set-up-a-private-action-runner
[3]: https://hub.docker.com/r/datadog/private-action-runner-dev
[4]: https://app.datadoghq.com/workflow/
[5]: https://app.datadoghq.com/app-builder/
[6]: https://api.datadoghq.com/api/v2/on-prem-management-service/runner/latest-image
[7]: https://app.datadoghq.com/organization-settings/remote-config?resource_type=agents
[8]: https://github.com/DataDog/helm-charts/blob/main/charts/private-action-runner/CHANGELOG.md
[9]: https://github.com/DataDog/helm-charts/blob/main/charts/private-action-runner/values.yaml
[10]: https://app.datadoghq.com/actions/action-catalog#/com.datadoghq.script.runPredefinedScript
Loading