
Security News
Open Source CAI Framework Handles Pen Testing Tasks up to 3,600× Faster Than Humans
CAI is a new open source AI framework that automates penetration testing tasks like scanning and exploitation up to 3,600× faster than humans.
Infrable is an Infrastructure as Code tool written in Python. It lets you manage hosts,
services, configuration templates, deployments, and more—all from a single Python file
(named infra.py
).
Install Infrable:
pip install -U infrable
Bootstrap a New Project:
infrable init
This command creates the basic project structure you’ll need.
In Infrable, you describe your infrastructure in a single file (named infra.py
). Here
you define all your hosts and the services running on them.
Example infra.py
:
from infrable import Host, Service
# Define your hosts
dev_host = Host(fqdn="dev.example.com", ip="127.0.0.1")
beta_host = Host(fqdn="beta.example.com", ip="127.0.0.1")
prod_host = Host(fqdn="prod.example.com", ip="127.0.0.1")
# Define services on the hosts
dev_web = Service(host=dev_host, port=8080)
beta_web = Service(host=beta_host, port=8080)
prod_web = Service(host=prod_host, port=8080)
dev_nginx = Service(host=dev_host, port=80)
beta_nginx = Service(host=beta_host, port=80)
prod_nginx = Service(host=prod_host, port=80)
View your hosts and services:
infrable hosts
infrable services
Templates let you manage configuration files dynamically. You write these using Jinja2 syntax and include metadata (like file paths and permissions) as header comments.
Add a template prefix in infra.py
:
template_prefix = "https://github.com/username/repository/blob/main"
Example: Nginx configuration template (templates/nginx/web.j2
):
# ---
# src: {{ template_prefix }}/{{ _template.src }}
# dest:
# - {{ dev_nginx.host }}:/etc/nginx/sites-enabled/web
# - {{ beta_nginx.host }}:/etc/nginx/sites-enabled/web
# - {{ prod_nginx.host }}:/etc/nginx/sites-enabled/web
# chmod: 644
# chown: root:root
# ---
server {
listen {{ dev_nginx.port }};
listen [::]:{{ dev_nginx.port }};
server_name {{ dev_nginx.host.fqdn }} www.{{ dev_nginx.host.fqdn }};
location / {
proxy_pass http://127.0.0.1:{{ dev_web.port }};
include proxy_params;
}
location /robots.txt {
root /var/www/html;
}
}
Notes:
- The
template_prefix
and*_nginx
variables are defined ininfra.py
.- The
_template.src
variable is automatically available in all templates.- The
dest
metadata field specifies the target path on the host.- The
chmod
andchown
metadata fields set file permissions and ownership.- There are other metadata fields you can use, like
execute
andskip
.- You can also declare multiple destinations with different chmod, chown values and context variables using yaml list syntax.
Example: A template script with destination as list (templates/nginx/robots.txt.sh.j2
):
#!/usr/bin/env bash
# ---
# src: {{ template_prefix }}/{{ _template.src }}
# dest:
# - loc: {{ dev_nginx.host }}:/root/init/robots.txt.sh
# ctx:
# disallow: "/"
# - loc: {{ beta_nginx.host }}:/root/init/robots.txt.sh
# ctx:
# disallow: "/"
# - loc: {{ prod_nginx.host }}:/root/init/robots.txt.sh
# ctx:
# disallow: ""
# execute: true
# ---
set -euxo pipefail
if [ ! -d /var/www/html ]; then
mkdir -p /var/www/html
fi
cat > /var/www/html/robots.txt <<EOF
User-agent: *
Disallow: {{ disallow }}
EOF
Notes:
- The
execute: true
metadata flag tells Infrable to execute the script on the remote host.- The value of
disallow
is set based on the context variables declared in the template header.
Before pushing configuration changes, Infrable compares your new files with those currently deployed. This helps you catch unintended changes. It also keeps a backup of the current configuration, so you can roll back if needed.
Deploy your files:
infrable files deploy [path]
## Same as
# infrable files gen [path]
# infrable files pull
# infrable files backup
# infrable files push
This command performs several steps:
You can run the same workflow in Python:
import infrable.files
infrable.files.deploy(path)
## Same as
# infrable.files.gen(path)
# infrable.files.pull()
# infrable.files.backup()
# infrable.files.push()
A simplified flowchart of the process:
flowchart TD;
A[Generate new files] --> B[Pull current files];
B --> C[Backup current files];
C --> D[Compare new vs. current];
D --> E{Differences?};
E -- Yes --> F[Show diff & confirm push];
E -- No --> G[Clean up temporary files];
F --> H[Push changes];
If you need to roll back changes, use the recover workflow:
infrable files recover [path]
## Same as
# infrable files revert [path]
# infrable files push
Or in Python:
import infrable.files
infrable.files.recover(path)
## Same as
# infrable.files.revert(path)
# infrable.files.push()
Infrable allows you to execute commands remotely on your defined hosts.
Run a command on a specific host:
infrable remote dev_host "sudo systemctl reload nginx"
Run on a service:
infrable remote dev_nginx "sudo systemctl reload nginx"
Run on all hosts affected by a file change:
infrable remote affected-hosts "sudo systemctl reload nginx"
Or combine with file diff:
infrable files affected-hosts | infrable remote - "sudo systemctl reload nginx"
Tasks are groups of commands that simplify repeated actions. Define them in infra.py
.
Example Task:
import typer
# Add a task group for the dev_nginx service
dev_nginx.typer = typer.Typer(help="Tasks for dev_nginx.")
@dev_nginx.typer.command(name="reload")
def reload_dev_nginx():
"""Test configuration and reload the Nginx service."""
assert dev_nginx.host, "Service must have a host to reload"
# Run: sudo nginx -t
dev_nginx.host.remote().sudo.nginx("-t")
# Run: sudo systemctl reload nginx
dev_nginx.host.remote().sudo.systemctl.reload.nginx()
Run the task:
infrable dev-nginx reload
Workflows let you combine tasks into a complete deployment process.
Example Workflow:
from infrable import concurrentcontext, paths
deploy = typer.Typer(help="Deployment workflows.")
@deploy.command(name="dev-nginx")
def deploy_dev_nginx():
"""Deploy dev_nginx configuration."""
# Deploy the Nginx configuration files
files.deploy(paths.templates / "nginx")
# Test the Nginx configuration and reload the service concurrently
cmd = "sudo nginx -t && sudo systemctl reload nginx && echo success || echo failed"
fn = lambda host: (host, host.remote().sudo(cmd))
with concurrentcontext(fn, files.affected_hosts()) as results:
for host, result in results:
print(f"{host}: {result}")
Run the workflow:
infrable deploy dev-nginx
Environments (like dev, beta, prod) let you use the same templates and tasks for different deployment targets.
Define environments and a switch in infra.py
:
from infrable import Switch, Host, Service
# Define environment names
dev = "dev"
beta = "beta"
prod = "prod"
environments = {dev, beta, prod}
# Create a switch for environments (default is dev)
env = Switch(environments, init=dev)
current_env = env()
# Define hosts for each environment
dev_host = Host(fqdn="dev.example.com", ip="127.0.0.1")
beta_host = Host(fqdn="beta.example.com", ip="127.0.0.2")
prod_host = Host(fqdn="prod.example.com", ip="127.0.0.3")
# Use the switch to select hosts based on environment
managed_hosts = env(
dev=[dev_host],
beta=[beta_host],
prod=[prod_host]
)
# Define a service using a strict switch to choose the host
web = Service(
host=env.strict(dev=dev_host, beta=beta_host, prod=prod_host),
port=8080
)
Update Templates to Use Environment-Specific Values:
For example, in templates/nginx/proxy_params.j2
:
# ---
# src: {{ template_prefix }}/{{ _template.src }}
# dest:
# {% for host in managed_hosts %}
# - {{ host }}:/etc/nginx/proxy_params
# {% endfor %}
# chmod: 644
# chown: root:root
# ---
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
Note: Yes, you can use loops in template headers!
Managing the Environment Switch:
# Switch to a specific environment
infrable switch env [dev|beta|prod]
# Check the current environment
infrable switch env
# List available environments
infrable switch env --options
# Shortcut alias (if switch is named "env")
infrable env [dev|beta|prod]
# List all switches
infrable switches
Keep sensitive information (like secret keys) out of your version control by storing them in separate files.
Example in infra.py
:
from infrable import Meta, readfile
# Read a secret key from a file
common_secret_key = readfile("secrets/common/secret_key")
# Attach secret metadata to a service
web = Service(
meta=Meta(secret_key=common_secret_key),
host=env(dev=dev_host, beta=beta_host, prod=prod_host),
port=8080
)
Tip: Add your secrets folder to .gitignore
:
echo /secrets/ >> .gitignore
You can add custom Python modules to extend Infrable’s functionality.
Example module (modules/mycloud.py
):
from dataclasses import dataclass
from typer import Typer
from infrable import Host, infra
@dataclass
class MyCloud:
"""Custom module for MyCloud operations."""
secret_api_key: str
typer: Typer | None = None
def provision_ubuntu_host(self, fqdn: str):
ip = self.api.create_ubuntu_host(fqdn)
return MyCloudUbuntuHost(fqdn=fqdn, ip=ip)
@dataclass
class MyCloudUbuntuHost(Host):
"""Customized Ubuntu host for MyCloud."""
def setup(self):
self.install_mycloud_agent()
def install_mycloud_agent(self):
raise NotImplementedError
workflows = Typer()
@workflows.command()
def provision_ubuntu_host(fqdn: str, setup: bool = True):
"""Provision an Ubuntu host."""
# Get the MyCloud instance from infra.py
cloud = next(iter(infra.item_types[MyCloud].values()))
host = cloud.provision_ubuntu_host(fqdn)
if setup:
host.setup()
name = fqdn.split(".")[0].replace("-", "_")
print("Add the host to the infra.py file.")
print(f"{name} = {repr(host)}")
Plug the module into your infra.py
:
from modules import mycloud
# Integrate the custom module with Infrable
cloud = mycloud.MyCloud(secret_api_key=readfile("secrets/mycloud/secret_api_key"))
cloud.typer = mycloud.workflows
Run the module workflow:
infrable cloud --help
You’ve now learned how to:
With these building blocks, even new developers can start managing infrastructure as code using Infrable. Happy coding!
FAQs
Manage infrastructure as a Python dev
We found that infrable demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
CAI is a new open source AI framework that automates penetration testing tasks like scanning and exploitation up to 3,600× faster than humans.
Security News
Deno 2.4 brings back bundling, improves dependency updates and telemetry, and makes the runtime more practical for real-world JavaScript projects.
Security News
CVEForecast.org uses machine learning to project a record-breaking surge in vulnerability disclosures in 2025.