up
Some checks failed
LNM Migration CI / build-runner (push) Has been cancelled
Ledger OpenAPI CI / deprecation-check (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Airgap Sealed CI Smoke / sealed-smoke (push) Has been cancelled
Ledger Packs CI / build-pack (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
Ledger OpenAPI CI / validate-oas (push) Has been cancelled
Ledger OpenAPI CI / check-wellknown (push) Has been cancelled
Ledger Packs CI / verify-pack (push) Has been cancelled
LNM Migration CI / validate-metrics (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled

This commit is contained in:
StellaOps Bot
2025-12-14 18:33:02 +02:00
parent d233fa3529
commit 2e70c9fdb6
51 changed files with 5958 additions and 75 deletions

181
deploy/ansible/README.md Normal file
View File

@@ -0,0 +1,181 @@
# Zastava Agent Ansible Deployment
Ansible playbook for deploying StellaOps Zastava Agent on VM/bare-metal hosts.
## Prerequisites
- Ansible 2.10 or later
- Target hosts must have:
- Docker installed and running
- SSH access with sudo privileges
- systemd as init system
- Internet access (for downloading agent binaries) OR local artifact repository
## Quick Start
1. **Create inventory file:**
```bash
cp inventory.yml.sample inventory.yml
```
2. **Edit inventory with your hosts and configuration:**
```yaml
zastava_agents:
hosts:
your-host:
ansible_host: 192.168.1.100
ansible_user: ubuntu
vars:
zastava_tenant: your-tenant
scanner_backend_url: https://scanner.internal
```
3. **Run the playbook:**
```bash
ansible-playbook -i inventory.yml zastava-agent.yml
```
## Configuration Variables
### Required Variables
| Variable | Description |
|----------|-------------|
| `zastava_tenant` | Tenant identifier for multi-tenancy isolation |
| `scanner_backend_url` | URL of the Scanner backend service |
### Optional Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `zastava_version` | `latest` | Agent version to deploy |
| `zastava_node_name` | hostname | Override node name in events |
| `zastava_health_port` | `8080` | Health check HTTP port |
| `docker_socket` | `/var/run/docker.sock` | Docker socket path |
| `zastava_log_level` | `Information` | Serilog log level |
| `scanner_backend_insecure` | `false` | Allow HTTP backend (NOT for production) |
| `download_base_url` | `https://releases.stellaops.org` | Base URL for agent downloads |
### Advanced Variables
| Variable | Description |
|----------|-------------|
| `zastava_extra_env` | Dictionary of additional environment variables |
## Directory Structure
After deployment, the agent is installed with the following structure:
```
/opt/stellaops/zastava-agent/ # Agent binaries
/etc/stellaops/zastava-agent.env # Environment configuration
/var/lib/zastava-agent/ # Data directory
/var/lib/zastava-agent/runtime-events/ # Event buffer (disk-backed)
/etc/systemd/system/zastava-agent.service # systemd unit
```
## Post-Deployment Verification
### Check Service Status
```bash
systemctl status zastava-agent
```
### View Logs
```bash
journalctl -u zastava-agent -f
```
### Health Endpoints
| Endpoint | Description |
|----------|-------------|
| `/healthz` | Liveness probe - agent is running |
| `/readyz` | Readiness probe - agent can process events |
| `/livez` | Alias for liveness probe |
```bash
curl http://localhost:8080/healthz
curl http://localhost:8080/readyz
```
## Air-Gapped Deployment
For air-gapped environments:
1. Download agent tarball to a local artifact server
2. Set `download_base_url` to your local server:
```yaml
download_base_url: https://artifacts.internal/stellaops
```
3. Ensure the URL structure matches:
`{download_base_url}/zastava-agent/{version}/zastava-agent-linux-{arch}.tar.gz`
## Security Notes
### Docker Socket Access
The agent requires read access to the Docker socket to monitor container events.
The service runs as the `zastava-agent` user in the `docker` group.
See `docs/modules/zastava/operations/docker-socket-permissions.md` for security
considerations and alternative configurations.
### systemd Hardening
The service unit includes security hardening:
- `NoNewPrivileges=true` - Prevent privilege escalation
- `ProtectSystem=strict` - Read-only system directories
- `PrivateTmp=true` - Isolated /tmp
- `ProtectKernelTunables=true` - No kernel parameter modification
- Resource limits on file descriptors and memory
## Troubleshooting
### Agent Won't Start
1. Check Docker service: `systemctl status docker`
2. Verify Docker socket permissions: `ls -la /var/run/docker.sock`
3. Check agent logs: `journalctl -u zastava-agent -e`
### Cannot Connect to Backend
1. Verify network connectivity: `curl -I ${scanner_backend_url}/healthz`
2. Check TLS certificates if using HTTPS
3. Ensure firewall allows outbound connections
### Events Not Being Sent
1. Check event buffer directory permissions
2. Verify health endpoint returns healthy: `curl localhost:8080/readyz`
3. Check agent logs for connection errors
## Uninstallation
To remove the agent:
```bash
# Stop and disable service
sudo systemctl stop zastava-agent
sudo systemctl disable zastava-agent
# Remove files
sudo rm -rf /opt/stellaops/zastava-agent
sudo rm -f /etc/stellaops/zastava-agent.env
sudo rm -f /etc/systemd/system/zastava-agent.service
sudo rm -rf /var/lib/zastava-agent
# Remove user
sudo userdel zastava-agent
# Reload systemd
sudo systemctl daemon-reload
```

View File

@@ -0,0 +1,58 @@
[Unit]
Description=StellaOps Zastava Agent - Container Runtime Monitor
Documentation=https://docs.stellaops.org/zastava/agent/
After=network-online.target docker.service containerd.service
Wants=network-online.target
Requires=docker.service
[Service]
Type=notify
ExecStart=/opt/stellaops/zastava-agent/StellaOps.Zastava.Agent
WorkingDirectory=/opt/stellaops/zastava-agent
Restart=always
RestartSec=5
# Environment configuration
EnvironmentFile=-/etc/stellaops/zastava-agent.env
Environment=DOTNET_ENVIRONMENT=Production
Environment=ASPNETCORE_ENVIRONMENT=Production
# User and permissions
User=zastava-agent
Group=docker
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
PrivateDevices=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictSUIDSGID=true
# Allow read access to Docker socket
ReadWritePaths=/var/run/docker.sock
ReadWritePaths=/var/lib/zastava-agent
# Capabilities
CapabilityBoundingSet=
AmbientCapabilities=
# Resource limits
LimitNOFILE=65536
LimitNPROC=4096
MemoryMax=512M
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=zastava-agent
# Watchdog (5 minute timeout)
WatchdogSec=300
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,46 @@
---
# Sample Ansible Inventory for Zastava Agent Deployment
#
# Copy this file to inventory.yml and customize for your environment.
# Then run: ansible-playbook -i inventory.yml zastava-agent.yml
all:
children:
zastava_agents:
hosts:
# Add your VM/bare-metal hosts here
vm-node-1:
ansible_host: 192.168.1.101
ansible_user: ubuntu
vm-node-2:
ansible_host: 192.168.1.102
ansible_user: ubuntu
# Example with SSH key
vm-node-3:
ansible_host: 192.168.1.103
ansible_user: root
ansible_ssh_private_key_file: ~/.ssh/stellaops_key
vars:
# Required: Set these for your environment
zastava_tenant: my-tenant
scanner_backend_url: https://scanner.example.com
# Optional: Override node name per host
# zastava_node_name: custom-node-name
# Optional: Change health check port
# zastava_health_port: 8080
# Optional: Custom Docker socket path
# docker_socket: /var/run/docker.sock
# Optional: Set log level (Verbose, Debug, Information, Warning, Error)
# zastava_log_level: Information
# Optional: Allow insecure HTTP (NOT for production)
# scanner_backend_insecure: false
# Optional: Additional environment variables
# zastava_extra_env:
# CUSTOM_VAR: custom_value

View File

@@ -0,0 +1,40 @@
# StellaOps Zastava Agent Configuration
# Managed by Ansible - Do not edit manually
# Generated: {{ ansible_date_time.iso8601 }}
# Tenant identifier for multi-tenancy
ZASTAVA_TENANT={{ zastava_tenant }}
# Scanner backend URL
ZASTAVA_AGENT__Backend__BaseAddress={{ scanner_backend_url }}
{% if zastava_node_name is defined %}
# Node name override
ZASTAVA_NODE_NAME={{ zastava_node_name }}
{% endif %}
# Docker socket endpoint
ZASTAVA_AGENT__DockerEndpoint=unix://{{ docker_socket }}
# Event buffer path
ZASTAVA_AGENT__EventBufferPath={{ zastava_data_dir }}/runtime-events
# Health check port
ZASTAVA_AGENT__HealthCheck__Port={{ zastava_health_port }}
{% if scanner_backend_insecure | default(false) | bool %}
# WARNING: Insecure HTTP backend enabled
ZASTAVA_AGENT__Backend__AllowInsecureHttp=true
{% endif %}
{% if zastava_log_level is defined %}
# Logging level
Serilog__MinimumLevel__Default={{ zastava_log_level }}
{% endif %}
{% if zastava_extra_env is defined %}
# Additional environment variables
{% for key, value in zastava_extra_env.items() %}
{{ key }}={{ value }}
{% endfor %}
{% endif %}

View File

@@ -0,0 +1,232 @@
---
# Ansible Playbook for Zastava Agent VM/Bare-Metal Deployment
#
# Requirements:
# - Target hosts must have Docker installed and running
# - Ansible 2.10+ with community.docker collection
#
# Usage:
# ansible-playbook -i inventory.yml zastava-agent.yml \
# -e zastava_tenant=my-tenant \
# -e scanner_backend_url=https://scanner.internal
#
# Variables (can be set in inventory or via -e):
# zastava_tenant: Tenant identifier (required)
# scanner_backend_url: Scanner backend URL (required)
# zastava_version: Version to deploy (default: latest)
# zastava_node_name: Override node name (default: hostname)
# zastava_health_port: Health check port (default: 8080)
# docker_socket: Docker socket path (default: /var/run/docker.sock)
- name: Deploy StellaOps Zastava Agent
hosts: zastava_agents
become: true
vars:
zastava_version: "{{ zastava_version | default('latest') }}"
zastava_install_dir: /opt/stellaops/zastava-agent
zastava_config_dir: /etc/stellaops
zastava_data_dir: /var/lib/zastava-agent
zastava_user: zastava-agent
zastava_group: docker
zastava_health_port: "{{ zastava_health_port | default(8080) }}"
docker_socket: "{{ docker_socket | default('/var/run/docker.sock') }}"
download_base_url: "{{ download_base_url | default('https://releases.stellaops.org') }}"
pre_tasks:
- name: Validate required variables
ansible.builtin.assert:
that:
- zastava_tenant is defined and zastava_tenant | length > 0
- scanner_backend_url is defined and scanner_backend_url | length > 0
fail_msg: |
Required variables not set.
Please provide:
- zastava_tenant: Your tenant identifier
- scanner_backend_url: Scanner backend URL
- name: Check Docker service is running
ansible.builtin.systemd:
name: docker
state: started
check_mode: true
register: docker_status
- name: Fail if Docker is not available
ansible.builtin.fail:
msg: "Docker service is not running on {{ inventory_hostname }}"
when: docker_status.status.ActiveState != 'active'
tasks:
# =========================================================================
# User and Directory Setup
# =========================================================================
- name: Create zastava-agent system user
ansible.builtin.user:
name: "{{ zastava_user }}"
comment: StellaOps Zastava Agent
system: true
shell: /usr/sbin/nologin
groups: "{{ zastava_group }}"
create_home: false
state: present
- name: Create installation directory
ansible.builtin.file:
path: "{{ zastava_install_dir }}"
state: directory
owner: "{{ zastava_user }}"
group: "{{ zastava_group }}"
mode: '0755'
- name: Create configuration directory
ansible.builtin.file:
path: "{{ zastava_config_dir }}"
state: directory
owner: root
group: root
mode: '0755'
- name: Create data directory
ansible.builtin.file:
path: "{{ zastava_data_dir }}"
state: directory
owner: "{{ zastava_user }}"
group: "{{ zastava_group }}"
mode: '0750'
- name: Create event buffer directory
ansible.builtin.file:
path: "{{ zastava_data_dir }}/runtime-events"
state: directory
owner: "{{ zastava_user }}"
group: "{{ zastava_group }}"
mode: '0750'
# =========================================================================
# Download and Install Agent
# =========================================================================
- name: Determine architecture
ansible.builtin.set_fact:
arch_suffix: "{{ 'x64' if ansible_architecture == 'x86_64' else 'arm64' if ansible_architecture == 'aarch64' else ansible_architecture }}"
- name: Download Zastava Agent binary
ansible.builtin.get_url:
url: "{{ download_base_url }}/zastava-agent/{{ zastava_version }}/zastava-agent-linux-{{ arch_suffix }}.tar.gz"
dest: /tmp/zastava-agent.tar.gz
mode: '0644'
register: download_result
retries: 3
delay: 5
- name: Extract Zastava Agent
ansible.builtin.unarchive:
src: /tmp/zastava-agent.tar.gz
dest: "{{ zastava_install_dir }}"
remote_src: true
owner: "{{ zastava_user }}"
group: "{{ zastava_group }}"
extra_opts:
- --strip-components=1
notify: Restart zastava-agent
- name: Make agent binary executable
ansible.builtin.file:
path: "{{ zastava_install_dir }}/StellaOps.Zastava.Agent"
mode: '0755'
- name: Clean up downloaded archive
ansible.builtin.file:
path: /tmp/zastava-agent.tar.gz
state: absent
# =========================================================================
# Configuration
# =========================================================================
- name: Deploy environment configuration
ansible.builtin.template:
src: zastava-agent.env.j2
dest: "{{ zastava_config_dir }}/zastava-agent.env"
owner: root
group: "{{ zastava_group }}"
mode: '0640'
notify: Restart zastava-agent
# =========================================================================
# systemd Service
# =========================================================================
- name: Install systemd service unit
ansible.builtin.copy:
src: zastava-agent.service
dest: /etc/systemd/system/zastava-agent.service
owner: root
group: root
mode: '0644'
notify:
- Reload systemd
- Restart zastava-agent
- name: Enable and start zastava-agent service
ansible.builtin.systemd:
name: zastava-agent
state: started
enabled: true
daemon_reload: true
# =========================================================================
# Health Verification
# =========================================================================
- name: Wait for agent health endpoint
ansible.builtin.uri:
url: "http://localhost:{{ zastava_health_port }}/healthz"
method: GET
status_code: 200
register: health_result
retries: 30
delay: 2
until: health_result.status == 200
- name: Display agent status
ansible.builtin.debug:
msg: "Zastava Agent deployed successfully on {{ inventory_hostname }}"
handlers:
- name: Reload systemd
ansible.builtin.systemd:
daemon_reload: true
- name: Restart zastava-agent
ansible.builtin.systemd:
name: zastava-agent
state: restarted
# =============================================================================
# Post-deployment verification play
# =============================================================================
- name: Verify Zastava Agent Deployment
hosts: zastava_agents
become: false
gather_facts: false
tasks:
- name: Check agent readiness
ansible.builtin.uri:
url: "http://localhost:{{ zastava_health_port | default(8080) }}/readyz"
method: GET
return_content: true
register: ready_check
- name: Display deployment summary
ansible.builtin.debug:
msg: |
Zastava Agent Deployment Summary:
- Host: {{ inventory_hostname }}
- Status: {{ 'Ready' if ready_check.status == 200 else 'Not Ready' }}
- Health Endpoint: http://localhost:{{ zastava_health_port | default(8080) }}/healthz
- Tenant: {{ zastava_tenant }}
- Backend: {{ scanner_backend_url }}