Skip to content

Security ​

LXC AutoScale v2.0 includes several security hardening measures that are enabled by default.

SSH host key verification ​

By default, the daemon refuses connections to SSH hosts whose keys are not in the system's known_hosts file. This prevents Man-in-the-Middle attacks during remote execution.

Configuration ​

yaml
DEFAULT:
  ssh_host_key_policy: reject   # default, recommended
ValueBehavior
rejectRefuse unknown host keys. Requires the Proxmox host key to be present in ~/.ssh/known_hosts.
systemLoad system known_hosts and warn on unknown keys, but allow the connection.
autoAccept any host key. Deprecated. Equivalent to StrictHostKeyChecking=no. Will be removed in a future version.

Adding host keys ​

On the machine running the daemon:

bash
ssh-keyscan -H <proxmox_host> >> ~/.ssh/known_hosts

In Docker, mount a known_hosts file into the container or set the KNOWN_HOSTS_PATH environment variable. On first boot, the entrypoint will attempt to run ssh-keyscan automatically if no file is found.

Secret masking in logs ​

All log output (console and file) is processed by a masking filter that redacts values matching common secret patterns before writing to disk. This prevents accidental exposure of credentials in log files.

What is masked ​

  • Key-value pairs: password=..., token:..., api_key=...
  • Bearer tokens: Authorization: Bearer ...
  • Command-line passwords: sshpass -p ...
  • Long hex or base64 strings (32+ characters) that resemble tokens or keys

How it works ​

The SecretMaskingFilter is attached to the root Python logger at startup. It intercepts all log records and replaces matched patterns with ***REDACTED*** before the message reaches any handler (console, file, or JSON).

No configuration is needed. The filter is always active.

Environment variable expansion in YAML ​

Configuration values can reference environment variables using ${VAR} or ${VAR:-default} syntax. This avoids storing secrets in plaintext in the YAML file.

yaml
DEFAULT:
  ssh_password: ${SSH_PASSWORD}
  proxmox_api:
    token_value: ${PROXMOX_TOKEN:-not-configured}

If the variable is not set and no default is provided, the literal ${VAR} string is preserved unchanged.

Additionally, these environment variables override specific config keys directly, regardless of what the YAML file contains:

Environment variableOverrides
LXC_AUTOSCALE_SSH_PASSWORDssh_password
LXC_AUTOSCALE_SMTP_PASSWORDsmtp_password
LXC_AUTOSCALE_GOTIFY_TOKENgotify_token
LXC_AUTOSCALE_UPTIME_KUMA_WEBHOOKuptime_kuma_webhook_url

Configuration file permissions ​

On startup, the daemon checks the permissions of the YAML configuration file. If it is readable by group or other users, a warning is logged:

Config file /etc/lxc_autoscale/lxc_autoscale.yaml is readable by group/others (mode 644).
Recommend chmod 0600 to protect secrets.

Set restrictive permissions:

bash
chmod 600 /etc/lxc_autoscale/lxc_autoscale.yaml

Docker non-root execution ​

WARNING

The REST backend has been removed. It was never connected to the running daemon, so setting backend: api changed nothing while appearing to work. It is now refused at startup with an explanatory message rather than silently ignored. A real API backend is tracked as #56.

The intent below is that with a REST backend, and therefore no local pct commands, the Docker container could run as a non-root user. There is no such backend today: pct is what runs, and it needs root. Configuring the container as non-root produces a daemon that cannot act at all.

Set the LXC_RUN_AS_ROOT environment variable to false:

bash
docker run -d \
  -e LXC_RUN_AS_ROOT=false \
  -v /path/to/config.yaml:/app/lxc_autoscale.yaml \
  lxc-autoscale

This requires backend: api in the configuration. The CLI backend needs root for pct commands and will not work in non-root mode.

Proxmox API token permissions ​

When the REST API backend is connected, create a dedicated API token with minimal permissions rather than using root credentials.

In the Proxmox web UI:

  1. Go to Datacenter > Permissions > API Tokens
  2. Create a token for a user with only the permissions needed:
    • VM.Audit (read container status and config)
    • VM.Config.CPU (modify CPU settings)
    • VM.Config.Memory (modify memory settings)

Store the token value in an environment variable and reference it in the YAML:

yaml
DEFAULT:
  backend: api
  proxmox_api:
    host: 192.168.1.1
    user: autoscale@pve
    token_name: scaling
    token_value: ${PROXMOX_API_TOKEN}
    verify_ssl: true

Configuration validation ​

All configuration is validated at startup using Pydantic models. Invalid values cause the daemon to exit with a clear error message rather than running with broken settings.

Validated constraints include:

  • cpu_lower_threshold must be less than cpu_upper_threshold
  • memory_lower_threshold must be less than memory_upper_threshold
  • min_cores must be less than or equal to max_cores
  • behaviour must be one of normal, conservative, aggressive
  • backend must be one of cli, api
  • ssh_host_key_policy must be one of reject, system, auto

Released under the MIT License. · Privacy & legal