Cua Docs

Pass secrets into a sandbox

Read secrets from the host and inject them into a sandbox at runtime.

Pass secrets from the host environment into a sandbox at runtime, and keep image metadata for non-sensitive configuration.

Set the Cua API key#

The Cua API key is read from CUA_API_KEY environment variable. You can also pass it explicitly:

async with Sandbox.ephemeral(Image.linux(), api_key=my_key) as sb:
    ...

Inject secrets at runtime#

Read secrets from the host environment, then inject them into the sandbox with sb.shell.run.

import os
import asyncio
from cua import Sandbox, Image
 
async def main():
    db_url = os.environ['DATABASE_URL']
    gh_token = os.environ['GITHUB_TOKEN']
 
    async with Sandbox.ephemeral(Image.linux()) as sb:
        await sb.shell.run(f"export DATABASE_URL='{db_url}'")
        await sb.shell.run(f"export GITHUB_TOKEN='{gh_token}'")
        await sb.shell.run('python /app/main.py')
 
asyncio.run(main())

For multi-command sessions, use a wrapper script:

script = f"""
export DATABASE_URL='{db_url}'
export GITHUB_TOKEN='{gh_token}'
python /app/main.py
"""
result = await sb.shell.run(script)

Non-sensitive config with Image.env()#

Use Image.env() for non-sensitive config, not for secrets.

img = (
    Image.linux()
    .apt_install('python3')
    .env(
        LOG_LEVEL='info',
        APP_ENV='production',
        PORT='8080',
    )
)

.env() values are stored in the Image spec and visible to anyone who can inspect it. Do not use .env() for API keys, passwords, or tokens.

Copy secret files into the sandbox#

Copy SSH keys, certificates, and other secret files into the sandbox at runtime, then set file permissions.

async with Sandbox.ephemeral(Image.linux()) as sb:
    with open(os.path.expanduser('~/.ssh/id_rsa')) as f:
        key_content = f.read()
    await sb.shell.run('mkdir -p /root/.ssh && chmod 700 /root/.ssh')
    await sb.shell.run(f"cat > /root/.ssh/id_rsa << 'EOF'\n{key_content}\nEOF")
    await sb.shell.run('chmod 600 /root/.ssh/id_rsa')

For files safe to bake in, use Image.copy():

img = Image.linux().copy('./app-config.json', '/app/config.json')

Best practices#

DoDon't
Read secrets from host environment variablesHardcode secrets in Python source
Inject secrets at runtime via sb.shell.runStore secrets in Image.env()
Use .env files + python-dotenv locallyCommit .env files to version control
Use your CI/CD provider's secret managerLog or print secret values