VM & LXC Security Standard¶
Purpose¶
This document defines the baseline security, access model, directory layout, and secret delivery standard for all VM and LXC instances used for Appcircle workloads.
Design Principle¶
Identity verification is performed at the Guacamole and SSO layer. VMs use two shared accounts — sysadmin for infrastructure operations and appcircle for application operations. Access to each account is controlled through separate Guacamole connection groups with SSO-based group membership.
Attribution is maintained through Guacamole session logs and recordings, not through per-operator VM accounts.
User Model¶
Each VM/LXC must contain the following accounts.
| Account | Role | Access path |
|---|---|---|
root |
System default | Privilege escalation only — no direct SSH login |
sysadmin |
Shared administrative account, member of sudo |
Guacamole vm-<name>-admin connection group |
appcircle |
Dual-role: application service identity and developer operational identity | Guacamole vm-<name>-app connection group |
Operational distinction:
- Infrastructure operators use
sysadminfor OS-level tasks - Developers and deployment operators use
appcirclefor application operations - Neither group needs to switch accounts during normal operations
Note
No per-operator accounts exist on the VM. Operators must not know the sysadmin or appcircle passwords directly. Both passwords are stored in OpenBao and injected into Guacamole through a controlled credential flow.
Core Security Rules¶
Root Login¶
- Direct SSH login as
rootis forbidden PermitRootLogin nomust be set- Root access must only be obtained through
sudo
SSH Hardening¶
Minimum required sshd_config settings:
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
Port <custom-port>
MaxAuthTries 3
LoginGraceTime 30
ClientAliveInterval 300
ClientAliveCountMax 2
X11Forwarding no
AllowTcpForwarding no
PermitEmptyPasswords no
- SSH must not listen on port 22
- SSH access must be restricted to the Guacamole source IP or approved subnet
- Preferred key type:
Ed25519. RSA minimum: 4096-bit. DSA must not be used.
Network Exposure¶
- Only required ports must be opened
- Internal services must not be exposed publicly unless explicitly required
- East-west access between systems should be minimized and documented
Guacamole Access Model¶
Two Guacamole connection groups must be defined per VM.
| Connection group | Target account | Who uses it |
|---|---|---|
vm-<name>-admin |
sysadmin |
Infrastructure and ops team |
vm-<name>-app |
appcircle |
Developers and deployment operators |
Access to each connection group is governed by SSO group membership.
Mandatory Safeguards¶
Session recording:
- Every Guacamole session must be recorded
- Recordings must be stored on central storage, not on the Guacamole host
- Minimum retention: 90 days
Credential isolation:
- Both passwords must be stored in OpenBao and injected into Guacamole
- Operators must never see or retrieve either password directly
- Passwords must be randomly generated, at least 32 characters, and rotated every 90 days
Network enforcement:
- SSH must accept connections only from the Guacamole source IP or approved subnet
- No direct SSH access from any other source
Directory Layout¶
/opt/appcircle/
bin/ operational scripts
config/ configuration templates and rendered secret files
compose/ Docker Compose files
releases/ versioned release content
shared/
logs/
data/
tmp/
/home/appcircle/
.ssh/
scripts/
workspace/
/opt/appcircle is the authoritative application root. It must be owned by appcircle:appcircle.
/home/appcircle is the service user's working area for user-scoped helpers and temporary files.
Ownership and Permissions¶
/opt/appcircle appcircle:appcircle 0755
/opt/appcircle/config appcircle:appcircle 0750
/opt/appcircle/config/role-id root:root 0600
/opt/appcircle/config/secret-id root:root 0600
/opt/appcircle/config/*.env root:root 0600 (rendered secret files)
/opt/appcircle/config/*.env.tpl root:root 0644 (templates, no secret values)
Rendered secret files are owned by root so that neither sysadmin nor appcircle can read them directly. Only the processes running as root (OpenBao Agent, Docker Compose stack) access these files.
Secret Delivery¶
Secrets must be delivered through OpenBao Agent.
- OpenBao Agent runs as a systemd service
- Agent authenticates using AppRole (
role-id+secret-id) - Agent renders secrets to files via templates
- The application reads rendered files and never contacts OpenBao directly
- Token TTL: 1 hour, auto-renewed by the agent
File permission model¶
/opt/appcircle/config/role-id root:root 0600
/opt/appcircle/config/secret-id root:root 0600
/opt/appcircle/config/app.env root:root 0600 (rendered output)
/opt/appcircle/config/app.env.tpl root:root 0644 (template)
See OpenBao for agent configuration details.
Native Application Service Users¶
For natively installed applications (nginx, PostgreSQL, OpenBao, etc.), use the upstream-defined service user — do not substitute appcircle.
| Application | Expected service user |
|---|---|
| nginx | www-data (Debian/Ubuntu) or nginx (RHEL) |
| PostgreSQL | postgres |
| OpenBao | openbao |
| Redis | redis |
appcircle retains its operational role (deployment scripts, configuration management) but must not be set as the runtime service user for third-party applications.
Secret delivery for native applications¶
When the application's service user differs from appcircle, choose one of:
| Option | Approach |
|---|---|
| Group access (preferred) | Add the service user to the appcircle group; set rendered file to 0640 appcircle:appcircle |
| Dedicated output path | Render directly to a path owned by the service user |
| systemd EnvironmentFile | Render an env file; reference it in the unit with EnvironmentFile= |
The chosen option must be documented in the deployment runbook.
Operational Tooling for the appcircle User¶
Makefile¶
A Makefile must be placed at /opt/appcircle/bin/Makefile. It serves as the single entry point for all operations the appcircle user performs on a VM. When a developer logs in via Guacamole, they run make help to see what actions are available — without needing to know the underlying systemctl commands or service names.
cd /opt/appcircle/bin
make help
The Makefile wraps sudo systemctl calls and journalctl log commands into named targets. This keeps the operational surface predictable and auditable.
Permissions:
/opt/appcircle/bin/Makefile appcircle:appcircle 0644
Scoped sudo via sudoers¶
The appcircle user must not have unrestricted sudo access. Service management permissions are granted per-service through a dedicated sudoers file under /etc/sudoers.d/.
Example for a Guacamole host (/etc/sudoers.d/appcircle-guacamole):
appcircle ALL=(root) NOPASSWD: /usr/bin/systemctl start guacamole-stack.service
appcircle ALL=(root) NOPASSWD: /usr/bin/systemctl stop guacamole-stack.service
appcircle ALL=(root) NOPASSWD: /usr/bin/systemctl restart guacamole-stack.service
appcircle ALL=(root) NOPASSWD: /usr/bin/systemctl status guacamole-stack.service
Rules:
- Only the specific service(s) relevant to the application are listed
openbao-agent.serviceand other infrastructure services must not be included —appcirclemust not be able to stop the secret agent- The sudoers file name must reflect the host or application context (e.g.,
appcircle-guacamole,appcircle-nginx)
Deployment flow for the appcircle user¶
Developer authenticates via SSO
↓
Opens vm-<name>-app connection in Guacamole
↓
Logged in as appcircle on the VM
↓
cd /opt/appcircle/bin && make help
↓
Runs make start / make restart / make logs
↓
sudo systemctl ... executed with scoped NOPASSWD permission
Docker Standard¶
If Docker is used:
appcircleis not in thedockergroup by default (Model A — controlled viasudowrappers)- Containers must run as non-root wherever possible
- Compose files:
/opt/appcircle/compose - Environment files:
/opt/appcircle/config - Volume data:
/opt/appcircle/shared
Onboarding and Offboarding¶
Onboarding:
- Grant SSO/IdP access
- Assign to the correct Guacamole connection group based on role
- No VM-level user creation required
Offboarding:
- Disable the IdP account to immediately revoke Guacamole access
- Rotate
sysadminandappcirclepasswords if there is any exposure risk - No VM-level user deletion required
Audit and Logging¶
Minimum events to log:
- SSH login attempts (successful and failed)
sudousage- Service start, stop, restart, and failure events
- OpenBao Agent authentication and render events
- Changes under
/opt/appcircle/configand/opt/appcircle/compose
Recommended tools: auditd for file and privilege auditing, tlog for interactive session recording, rsyslog for central log forwarding.
Minimum Baseline Checklist¶
- Root SSH login disabled
- SSH port changed from 22
- SSH firewall allows only Guacamole source IP
-
sysadminaccount created and insudo -
appcircleaccount created -
/opt/appcirclecreated with correct ownership - Session recording enabled for both Guacamole connection groups
-
sysadminpassword stored in OpenBao and injected via Guacamole -
appcirclepassword stored in OpenBao and injected via Guacamole - SSO group membership controls access to each connection group
- Firewall configured with minimum required rules
- OpenBao Agent configured and running
- Deployment procedure documented