feat: add hardened base and per-edition image overlays
Add the files that land in the image, organised as layered rootfs trees (base first, then the edition layer wins on conflict). - base: hardened kernel cmdline + sysctl, default-deny nftables, key-only ssh, persistent journald, module blacklist, no core dumps, snapshot timer units, motd. - server: Prometheus + auto-provisioned Grafana + Loki + promtail. - workstation: dev profile and desktop sysctl relaxations (perf, rootless containers). - cloud: cloud-init provisioning config.
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
# Arcline OS — Grafana dashboard provisioning (server edition)
|
||||
apiVersion: 1
|
||||
|
||||
providers:
|
||||
- name: Arcline
|
||||
orgId: 1
|
||||
folder: Arcline
|
||||
type: file
|
||||
disableDeletion: false
|
||||
allowUiUpdates: true
|
||||
updateIntervalSeconds: 30
|
||||
options:
|
||||
path: /etc/grafana/provisioning/dashboards
|
||||
@@ -0,0 +1,94 @@
|
||||
{
|
||||
"uid": "arcline-node-overview",
|
||||
"title": "Arcline Node Overview",
|
||||
"tags": ["arcline", "node"],
|
||||
"timezone": "browser",
|
||||
"schemaVersion": 39,
|
||||
"version": 1,
|
||||
"refresh": "30s",
|
||||
"time": { "from": "now-1h", "to": "now" },
|
||||
"panels": [
|
||||
{
|
||||
"id": 1,
|
||||
"title": "System load",
|
||||
"type": "timeseries",
|
||||
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 0 },
|
||||
"datasource": { "type": "prometheus", "uid": "Prometheus" },
|
||||
"targets": [
|
||||
{
|
||||
"expr": "node_load1",
|
||||
"legendFormat": "load1",
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"expr": "node_load5",
|
||||
"legendFormat": "load5",
|
||||
"refId": "B"
|
||||
}
|
||||
],
|
||||
"fieldConfig": {
|
||||
"defaults": { "unit": "short" },
|
||||
"overrides": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"title": "Memory used",
|
||||
"type": "timeseries",
|
||||
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 0 },
|
||||
"datasource": { "type": "prometheus", "uid": "Prometheus" },
|
||||
"targets": [
|
||||
{
|
||||
"expr": "(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100",
|
||||
"legendFormat": "% used",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"fieldConfig": {
|
||||
"defaults": { "unit": "percent", "max": 100, "min": 0 },
|
||||
"overrides": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"title": "Disk usage",
|
||||
"type": "gauge",
|
||||
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 8 },
|
||||
"datasource": { "type": "prometheus", "uid": "Prometheus" },
|
||||
"targets": [
|
||||
{
|
||||
"expr": "(1 - node_filesystem_avail_bytes{mountpoint=\"/\"} / node_filesystem_size_bytes{mountpoint=\"/\"}) * 100",
|
||||
"legendFormat": "/",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"fieldConfig": {
|
||||
"defaults": { "unit": "percent", "max": 100, "min": 0 },
|
||||
"overrides": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"title": "Network traffic",
|
||||
"type": "timeseries",
|
||||
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 8 },
|
||||
"datasource": { "type": "prometheus", "uid": "Prometheus" },
|
||||
"targets": [
|
||||
{
|
||||
"expr": "rate(node_network_receive_bytes_total[5m])",
|
||||
"legendFormat": "rx {{ $labels.device }}",
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"expr": "rate(node_network_transmit_bytes_total[5m])",
|
||||
"legendFormat": "tx {{ $labels.device }}",
|
||||
"refId": "B"
|
||||
}
|
||||
],
|
||||
"fieldConfig": {
|
||||
"defaults": { "unit": "Bps" },
|
||||
"overrides": []
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
# Arcline OS — Grafana datasource provisioning (server edition)
|
||||
# Grafana is installed from the upstream apt repo (see configure-system.sh /
|
||||
# docs/observability.md). These files auto-provision on first start.
|
||||
|
||||
apiVersion: 1
|
||||
|
||||
datasources:
|
||||
- name: Prometheus
|
||||
type: prometheus
|
||||
access: proxy
|
||||
url: http://localhost:9090
|
||||
isDefault: true
|
||||
editable: false
|
||||
|
||||
- name: Loki
|
||||
type: loki
|
||||
access: proxy
|
||||
url: http://localhost:3100
|
||||
isDefault: false
|
||||
editable: false
|
||||
35
overlays/server/etc/loki/loki.yml
Normal file
35
overlays/server/etc/loki/loki.yml
Normal file
@@ -0,0 +1,35 @@
|
||||
# Arcline OS — Loki configuration (server edition)
|
||||
# Single-node, filesystem storage, 14-day retention. Loki is installed from
|
||||
# the upstream tarball (see docs/observability.md).
|
||||
|
||||
auth_enabled: false
|
||||
|
||||
server:
|
||||
http_listen_port: 3100
|
||||
grpc_listen_port: 9095
|
||||
|
||||
common:
|
||||
path_prefix: /var/lib/loki
|
||||
storage:
|
||||
filesystem:
|
||||
chunks_directory: /var/lib/loki/chunks
|
||||
rules_directory: /var/lib/loki/rules
|
||||
replication_factor: 1
|
||||
ring:
|
||||
instance_addr: 127.0.0.1
|
||||
kvstore:
|
||||
store: inmemory
|
||||
|
||||
schema_config:
|
||||
configs:
|
||||
- from: 2024-01-01
|
||||
store: tsdb
|
||||
object_store: filesystem
|
||||
schema: v13
|
||||
index:
|
||||
prefix: index_
|
||||
period: 24h
|
||||
|
||||
limits_config:
|
||||
retention_period: 14d
|
||||
allow_structured_metadata: false
|
||||
43
overlays/server/etc/prometheus/arcline.rules.yml
Normal file
43
overlays/server/etc/prometheus/arcline.rules.yml
Normal file
@@ -0,0 +1,43 @@
|
||||
# Arcline OS — pre-built alerting rules (Prometheus)
|
||||
groups:
|
||||
- name: arcline-node
|
||||
rules:
|
||||
- alert: NodeDown
|
||||
expr: up == 0
|
||||
for: 2m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "{{ $labels.instance }} is unreachable"
|
||||
|
||||
- alert: HighCpuLoad
|
||||
expr: node_load1 / count(node_cpu_seconds_total{mode="idle"}) > 2
|
||||
for: 10m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "sustained load average > 2 on {{ $labels.instance }}"
|
||||
|
||||
- alert: DiskAlmostFull
|
||||
expr: (1 - node_filesystem_avail_bytes{fstype!~"tmpfs|overlay|squashfs"} / node_filesystem_size_bytes) * 100 > 85
|
||||
for: 10m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "filesystem {{ $labels.mountpoint }} on {{ $labels.instance }} > 85%"
|
||||
|
||||
- alert: RootDiskCritical
|
||||
expr: (1 - node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100 > 95
|
||||
for: 5m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "root filesystem on {{ $labels.instance }} > 95%"
|
||||
|
||||
- alert: ServiceRestarts
|
||||
expr: increase(node_systemd_unit_restart_total[15m]) > 2
|
||||
for: 0m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "unit {{ $labels.name }} restarting repeatedly on {{ $labels.instance }}"
|
||||
25
overlays/server/etc/prometheus/prometheus.yml
Normal file
25
overlays/server/etc/prometheus/prometheus.yml
Normal file
@@ -0,0 +1,25 @@
|
||||
# Arcline OS — Prometheus configuration (server edition)
|
||||
# Scrapes itself and node_exporter on the local host. Extension points for
|
||||
# the Arcline toolchain (arcline-uptime exposes :8081/metrics) are commented.
|
||||
|
||||
global:
|
||||
scrape_interval: 15s
|
||||
evaluation_interval: 15s
|
||||
external_labels:
|
||||
cluster: arcline
|
||||
|
||||
rule_files:
|
||||
- /etc/prometheus/arcline.rules.yml
|
||||
|
||||
scrape_configs:
|
||||
- job_name: prometheus
|
||||
static_configs:
|
||||
- targets: ["localhost:9090"]
|
||||
|
||||
- job_name: node
|
||||
static_configs:
|
||||
- targets: ["localhost:9100"]
|
||||
|
||||
# - job_name: arcline-uptime
|
||||
# static_configs:
|
||||
# - targets: ["localhost:8081"]
|
||||
31
overlays/server/etc/promtail/promtail.yml
Normal file
31
overlays/server/etc/promtail/promtail.yml
Normal file
@@ -0,0 +1,31 @@
|
||||
# Arcline OS — Promtail configuration (server edition)
|
||||
# Ships systemd journal + /var/log files to Loki. Zero telemetry: this only
|
||||
# talks to the local Loki instance on localhost.
|
||||
|
||||
server:
|
||||
http_listen_port: 9080
|
||||
grpc_listen_port: 0
|
||||
|
||||
positions:
|
||||
filename: /var/lib/promtail/positions.yaml
|
||||
|
||||
clients:
|
||||
- url: http://localhost:3100/loki/api/v1/push
|
||||
|
||||
scrape_configs:
|
||||
- job_name: systemd-journal
|
||||
journal:
|
||||
path: /var/log/journal
|
||||
max_age: 12h
|
||||
labels:
|
||||
job: systemd-journal
|
||||
relabel_configs:
|
||||
- source_labels: ["__journal__systemd_unit"]
|
||||
target_label: "unit"
|
||||
|
||||
- job_name: varlogs
|
||||
static_configs:
|
||||
- targets: [localhost]
|
||||
labels:
|
||||
job: varlogs
|
||||
__path__: /var/log/**/*.log
|
||||
Reference in New Issue
Block a user