Install es-python, the EyalSec Python runtime, on every instance you launch with Terraform. The module renders cloud-init user data that installs es-python at first boot, and each instance reports to your EyalSec dashboard as its own machine.
Your instances are already defined in Terraform, on AWS, Azure, Google Cloud or
any platform that runs cloud-init. This module adds one thing to them: user data
that installs es-python for the user your Python service runs as, the same way
the install command on the EyalSec Machines page does. It uses only the
hashicorp/cloudinit provider, so it fits next to whichever cloud provider you
use.
es-python runs your Python app unchanged and follows untrusted input to the SQL query, shell command or file path that uses it. You choose, per machine, whether it reports each flow or also stops it.
For: teams with an EyalSec account that includes es-python, on Linux images that run cloud-init (x86_64 or aarch64), Python 3.9 to 3.14, Terraform 1.3 or newer.
-
On your EyalSec dashboard, open Settings > API access and create a full-access key (API keys).
-
Store it in your cloud's secret store, for example as an SSM SecureString:
aws ssm put-parameter --name /eyalsec/api-key --type SecureString --value 'es2_...' -
Render the user data and give it to your instances:
module "es_python" { source = "EyalSec/es-python/cloudinit" version = "~> 1.0" authorized = true # see "Authorization" below install_user = "ec2-user" # the user your service runs as api_key_command = "aws ssm get-parameter --with-decryption --name /eyalsec/api-key --query Parameter.Value --output text" } resource "aws_instance" "app" { # ... user_data_base64 = module.es_python.user_data_base64 }
Until the module is listed on the Terraform Registry, use
source = "github.com/EyalSec/terraform-cloudinit-es-python?ref=v1.0.0".
The instance needs permission to read the parameter. The complete example, with the IAM role, is in examples/aws-ssm.
| Name | Default | Meaning |
|---|---|---|
authorized |
required | Must be true. See Authorization. |
api_key_command |
"" |
A shell command, run as root at first boot, that prints the API key. Recommended. |
api_key |
"" |
The API key itself (sensitive). It ends up in the user data; prefer api_key_command. |
install_secret |
"" |
A one-time install secret for one machine (sensitive). Single use, expires 10 minutes after it was issued, so only for one instance launched right away. |
install_user |
"root" |
The user es-python is installed for. Use the account your service runs under. |
create_user |
false |
Create install_user when it does not exist. |
machine_name |
"" |
The machine name. Empty uses the instance's host name at first boot. |
python_version |
"" |
3.9 to 3.14. Empty matches the image's own python3. |
eyalsec_url |
"https://eyalsec.com" |
Your EyalSec address. |
gzip |
true |
Compress the user data. |
Set exactly one of api_key_command, api_key and install_secret.
| Name | Meaning |
|---|---|
user_data_base64 |
The rendered cloud-init user data, base64 encoded. For user_data_base64 on AWS, custom_data on Azure, or user-data metadata on Google Cloud. |
script |
The first-boot script alone, to add as a part of your own cloudinit_config. |
Both are marked sensitive.
The script runs once, as root, when cloud-init runs user scripts:
- creates
install_userif you asked it to, and installscurlif the image has none; - writes the credential to a 0400 file in a private directory under
/run, owned byinstall_user; - as
install_user, finds the machine named after the instance on your account, adds it the first time with its build left to detection, gets a fresh one-time install secret, and runs the EyalSec installer; - removes the directory and the credential, whatever the outcome.
The installer's progress is in /var/log/cloud-init-output.log; it never
contains the key. es-python installs into the user's home (~/opt/,
~/.local/bin/es-python, ~/.eyalsec/). See
What it installs.
Anything on an instance that can read its user data (on most clouds, any
process that can reach the metadata service) can read what the user data
contains. With api_key_command, the user data holds only the command, and the
key exists on the instance for the length of the install. With api_key, the
key is in the user data and in your Terraform state for the instance's
lifetime, which is why api_key_command is the one to choose.
authorized = true is your confirmation that you own these instances or are
authorized to monitor them, that you will not use es-python to surveil third
parties, and that you are not located in or a national of an embargoed
destination and not on a denied-party list. It is the same statement as the
tick box on the Machines page. es-python may capture values from your program's
memory, including secrets and personal data, when untrusted data reaches a
monitored operation, so only run it on systems you are authorized to monitor.
- Each instance is one machine and counts toward your
machine limit. In a scaling
group, instances come and go: delete the machines of terminated instances on
the Machines page, or set
machine_nameso replacements reuse a name. - Machine names must be unique among instances running at the same time; a second install of one machine stops the first instance from reporting.
- Images. Bake the module's user data into each launch, not into an image: an install belongs to the instance it ran on, and a copy started elsewhere is reported as a clone.
- Running your service. Start it with
/home/<install_user>/.local/bin/es-pythonwhere it ranpython. See Running es-python.
es-python needs an EyalSec account. To get one, book a live demo; pricing is at eyalsec.com/pricing.
MIT. See LICENSE.