@chain305/x-security 0.2.6 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
- # Writ firewall — deploy-time DNS wrapper
1
+ # XSecurity firewall — deploy-time DNS wrapper
2
2
 
3
3
  The generator emits `iptables.rules` and `ip6tables.rules` with placeholder
4
- tokens of the form `@@WRIT_RESOLVE:<fqdn>@@` wherever a
4
+ tokens of the form `@@X_SECURITY_RESOLVE:<fqdn>@@` wherever a
5
5
  `request.schema.<field>.domainAllowlist` entry must be turned into a
6
6
  concrete `-d <addr>` clause. iptables itself has no DNS; resolution must
7
7
  happen on the host at deploy time and be refreshed periodically.
@@ -12,54 +12,54 @@ These scripts complete that flow.
12
12
 
13
13
  | File | Destination | Purpose |
14
14
  |------|-------------|---------|
15
- | `writ-resolve.sh` | `/usr/local/sbin/writ-resolve.sh` | One-shot resolver. Reads a template, emits a resolved ruleset. |
16
- | `writ-refresh.sh` | `/usr/local/sbin/writ-refresh.sh` | Periodic re-resolve + `iptables-restore` apply with flap detection. |
17
- | `writ-refresh.service` | `/etc/systemd/system/writ-refresh.service` | systemd `Type=oneshot` unit. |
18
- | `writ-refresh.timer` | `/etc/systemd/system/writ-refresh.timer` | systemd timer; runs every 5 minutes. |
19
- | `writ.logrotate` | `/etc/logrotate.d/writ` | Optional logrotate config for the refresh log. |
15
+ | `x-security-resolve.sh` | `/usr/local/sbin/x-security-resolve.sh` | One-shot resolver. Reads a template, emits a resolved ruleset. |
16
+ | `x-security-refresh.sh` | `/usr/local/sbin/x-security-refresh.sh` | Periodic re-resolve + `iptables-restore` apply with flap detection. |
17
+ | `x-security-refresh.service` | `/etc/systemd/system/x-security-refresh.service` | systemd `Type=oneshot` unit. |
18
+ | `x-security-refresh.timer` | `/etc/systemd/system/x-security-refresh.timer` | systemd timer; runs every 5 minutes. |
19
+ | `x-security.logrotate` | `/etc/logrotate.d/x-security` | Optional logrotate config for the refresh log. |
20
20
 
21
21
  ## Installation
22
22
 
23
23
  ```sh
24
24
  # 1. Place the scripts.
25
- install -m 0755 writ-resolve.sh /usr/local/sbin/writ-resolve.sh
26
- install -m 0755 writ-refresh.sh /usr/local/sbin/writ-refresh.sh
25
+ install -m 0755 x-security-resolve.sh /usr/local/sbin/x-security-resolve.sh
26
+ install -m 0755 x-security-refresh.sh /usr/local/sbin/x-security-refresh.sh
27
27
 
28
28
  # 2. Place the rule templates emitted by `lazy generate`.
29
- install -d /etc/writ
30
- install -m 0644 iptables.rules /etc/writ/rules.template
31
- install -m 0644 ip6tables.rules /etc/writ/rules6.template
29
+ install -d /etc/x-security
30
+ install -m 0644 iptables.rules /etc/x-security/rules.template
31
+ install -m 0644 ip6tables.rules /etc/x-security/rules6.template
32
32
 
33
- # 3. Replace the ${WRIT_APP_UID} placeholder in both templates with
33
+ # 3. Replace the ${X_SECURITY_APP_UID} placeholder in both templates with
34
34
  # the numeric uid of the application user (e.g. `id -u app-user`).
35
35
  APP_UID=$(id -u app-user)
36
- sed -i "s/\${WRIT_APP_UID}/${APP_UID}/g" \
37
- /etc/writ/rules.template /etc/writ/rules6.template
36
+ sed -i "s/\${X_SECURITY_APP_UID}/${APP_UID}/g" \
37
+ /etc/x-security/rules.template /etc/x-security/rules6.template
38
38
 
39
39
  # 4. Install + enable the systemd unit.
40
- install -m 0644 writ-refresh.service /etc/systemd/system/
41
- install -m 0644 writ-refresh.timer /etc/systemd/system/
40
+ install -m 0644 x-security-refresh.service /etc/systemd/system/
41
+ install -m 0644 x-security-refresh.timer /etc/systemd/system/
42
42
  systemctl daemon-reload
43
- systemctl enable --now writ-refresh.timer
43
+ systemctl enable --now x-security-refresh.timer
44
44
 
45
45
  # 5. (Optional) install logrotate snippet.
46
- install -m 0644 writ.logrotate /etc/logrotate.d/writ
46
+ install -m 0644 x-security.logrotate /etc/logrotate.d/x-security
47
47
  ```
48
48
 
49
- The timer runs `writ-refresh.sh` on boot and every 5 minutes
49
+ The timer runs `x-security-refresh.sh` on boot and every 5 minutes
50
50
  thereafter. The first run resolves the template, applies via
51
- `iptables-restore`, and snapshots to `/etc/writ/rules.applied`.
51
+ `iptables-restore`, and snapshots to `/etc/x-security/rules.applied`.
52
52
 
53
53
  ## Environment variables
54
54
 
55
55
  | Variable | Default | Effect |
56
56
  |----------|---------|--------|
57
- | `WRIT_APP_UID` | (none — required) | Numeric uid the rules scope to via `-m owner --uid-owner`. Substitute into the template before installing. |
58
- | `WRIT_LOG` | `/var/log/writ-resolve.log` | Resolver + refresh log path. Append-only. |
59
- | `WRIT_CONF_DIR` | `/etc/writ` | Where templates/current/applied/flap-history live. |
60
- | `WRIT_FLAP_MAX` | `5` | Max ruleset changes within the flap window before holding previous rules. |
61
- | `WRIT_FLAP_WINDOW` | `900` | Flap detection window in seconds (15 min default). |
62
- | `WRIT_RESOLVER` | `/usr/local/sbin/writ-resolve.sh` | Path to the resolver script (refresh wrapper uses this). |
57
+ | `X_SECURITY_APP_UID` | (none — required) | Numeric uid the rules scope to via `-m owner --uid-owner`. Substitute into the template before installing. |
58
+ | `X_SECURITY_LOG` | `/var/log/x-security-resolve.log` | Resolver + refresh log path. Append-only. |
59
+ | `X_SECURITY_CONF_DIR` | `/etc/x-security` | Where templates/current/applied/flap-history live. |
60
+ | `X_SECURITY_FLAP_MAX` | `5` | Max ruleset changes within the flap window before holding previous rules. |
61
+ | `X_SECURITY_FLAP_WINDOW` | `900` | Flap detection window in seconds (15 min default). |
62
+ | `X_SECURITY_RESOLVER` | `/usr/local/sbin/x-security-resolve.sh` | Path to the resolver script (refresh wrapper uses this). |
63
63
  | `IPTABLES_RESTORE` | `/sbin/iptables-restore` | Override path to `iptables-restore`. |
64
64
  | `IP6TABLES_RESTORE` | `/sbin/ip6tables-restore` | Override path to `ip6tables-restore`. |
65
65
 
@@ -67,17 +67,17 @@ thereafter. The first run resolves the template, applies via
67
67
 
68
68
  ```sh
69
69
  # stdin → stdout
70
- cat /etc/writ/rules.template | /usr/local/sbin/writ-resolve.sh
70
+ cat /etc/x-security/rules.template | /usr/local/sbin/x-security-resolve.sh
71
71
 
72
72
  # file → file, strict mode (default — exit 1 on any failed FQDN)
73
- /usr/local/sbin/writ-resolve.sh \
74
- --rules-file /etc/writ/rules.template \
75
- --out /etc/writ/rules.current
73
+ /usr/local/sbin/x-security-resolve.sh \
74
+ --rules-file /etc/x-security/rules.template \
75
+ --out /etc/x-security/rules.current
76
76
 
77
77
  # Lenient: drop only the unresolved rules, keep the rest.
78
- /usr/local/sbin/writ-resolve.sh --lenient \
79
- --rules-file /etc/writ/rules.template \
80
- --out /etc/writ/rules.current
78
+ /usr/local/sbin/x-security-resolve.sh --lenient \
79
+ --rules-file /etc/x-security/rules.template \
80
+ --out /etc/x-security/rules.current
81
81
  ```
82
82
 
83
83
  ## Security model
@@ -97,14 +97,14 @@ cat /etc/writ/rules.template | /usr/local/sbin/writ-resolve.sh
97
97
  script detects rapid change and freezes the previously-applied
98
98
  ruleset rather than thrashing iptables. Threshold is tunable.
99
99
  5. **Log integrity.** All resolution outcomes are written append-only to
100
- `$WRIT_LOG` with ISO-8601 timestamps. Rotation via logrotate
100
+ `$X_SECURITY_LOG` with ISO-8601 timestamps. Rotation via logrotate
101
101
  (NOT `copytruncate`) preserves append-only semantics.
102
102
 
103
103
  ## Troubleshooting
104
104
 
105
- - `systemctl status writ-refresh.timer` — is the timer scheduled?
106
- - `journalctl -u writ-refresh.service` — last few run outcomes.
107
- - `tail -f /var/log/writ-resolve.log` — per-FQDN resolution traces.
108
- - `iptables-save | grep writ` — what's actually in the kernel.
105
+ - `systemctl status x-security-refresh.timer` — is the timer scheduled?
106
+ - `journalctl -u x-security-refresh.service` — last few run outcomes.
107
+ - `tail -f /var/log/x-security-resolve.log` — per-FQDN resolution traces.
108
+ - `iptables-save | grep x-security` — what's actually in the kernel.
109
109
  - If you see the flap-throttle WARN: investigate DNS instability first;
110
110
  the wrapper is doing its job by refusing to apply churn.
@@ -1,18 +1,18 @@
1
1
  [Unit]
2
- Description=Writ firewall refresh (DNS-resolved allowlist apply)
3
- Documentation=https://github.com/writ/writ
2
+ Description=XSecurity firewall refresh (DNS-resolved allowlist apply)
3
+ Documentation=https://github.com/x-security/x-security
4
4
  After=network-online.target
5
5
  Wants=network-online.target
6
6
 
7
7
  [Service]
8
8
  Type=oneshot
9
- ExecStart=/usr/local/sbin/writ-refresh.sh
9
+ ExecStart=/usr/local/sbin/x-security-refresh.sh
10
10
  # Fail-closed: a failure here MUST NOT clear existing rules. The script
11
11
  # itself is responsible for that (it exits 0 on resolver failure to avoid
12
12
  # triggering systemd-restart loops that could thrash iptables).
13
13
  SuccessExitStatus=0
14
14
  # Hardening: the script only needs network + iptables. No private tmp
15
- # because the resolver writes /etc/writ/rules.current.
15
+ # because the resolver writes /etc/x-security/rules.current.
16
16
  ProtectSystem=false
17
17
  ProtectHome=true
18
18
  PrivateDevices=true
@@ -1,15 +1,15 @@
1
1
  #!/bin/sh
2
- # writ-refresh.sh — periodic re-resolution + apply for Writ rules.
2
+ # x-security-refresh.sh — periodic re-resolution + apply for XSecurity rules.
3
3
  #
4
4
  # Designed to run from a systemd timer (every 5 min by default). On each
5
5
  # tick:
6
- # 1. Resolve /etc/writ/rules.template via writ-resolve.sh
7
- # into /etc/writ/rules.current.
8
- # 2. Diff against /etc/writ/rules.applied — if unchanged, no-op.
6
+ # 1. Resolve /etc/x-security/rules.template via x-security-resolve.sh
7
+ # into /etc/x-security/rules.current.
8
+ # 2. Diff against /etc/x-security/rules.applied — if unchanged, no-op.
9
9
  # 3. If changed, apply via `iptables-restore` and snapshot
10
- # /etc/writ/rules.applied.
10
+ # /etc/x-security/rules.applied.
11
11
  # 4. Flap detection: if the resolved output changes more than
12
- # $WRIT_FLAP_MAX times within $WRIT_FLAP_WINDOW seconds,
12
+ # $X_SECURITY_FLAP_MAX times within $X_SECURITY_FLAP_WINDOW seconds,
13
13
  # hold the previous rules (do NOT apply the new ones) and warn.
14
14
  # This protects against DNS instability (round-robin churn,
15
15
  # misconfigured TTLs, or active DNS attacks).
@@ -21,7 +21,7 @@
21
21
 
22
22
  set -eu
23
23
 
24
- CONF_DIR="${WRIT_CONF_DIR:-/etc/writ}"
24
+ CONF_DIR="${X_SECURITY_CONF_DIR:-/etc/x-security}"
25
25
  TEMPLATE="${CONF_DIR}/rules.template"
26
26
  TEMPLATE6="${CONF_DIR}/rules6.template"
27
27
  CURRENT="${CONF_DIR}/rules.current"
@@ -29,13 +29,13 @@ CURRENT6="${CONF_DIR}/rules6.current"
29
29
  APPLIED="${CONF_DIR}/rules.applied"
30
30
  APPLIED6="${CONF_DIR}/rules6.applied"
31
31
  FLAP_LOG="${CONF_DIR}/.flap-history"
32
- LOG_FILE="${WRIT_LOG:-/var/log/writ-resolve.log}"
32
+ LOG_FILE="${X_SECURITY_LOG:-/var/log/x-security-resolve.log}"
33
33
 
34
34
  # Flap thresholds.
35
- FLAP_MAX="${WRIT_FLAP_MAX:-5}"
36
- FLAP_WINDOW="${WRIT_FLAP_WINDOW:-900}" # 15 minutes default
35
+ FLAP_MAX="${X_SECURITY_FLAP_MAX:-5}"
36
+ FLAP_WINDOW="${X_SECURITY_FLAP_WINDOW:-900}" # 15 minutes default
37
37
 
38
- RESOLVER="${WRIT_RESOLVER:-/usr/local/sbin/writ-resolve.sh}"
38
+ RESOLVER="${X_SECURITY_RESOLVER:-/usr/local/sbin/x-security-resolve.sh}"
39
39
  IPTABLES_RESTORE="${IPTABLES_RESTORE:-/sbin/iptables-restore}"
40
40
  IP6TABLES_RESTORE="${IP6TABLES_RESTORE:-/sbin/ip6tables-restore}"
41
41
 
@@ -1,6 +1,6 @@
1
1
  [Unit]
2
- Description=Writ firewall refresh timer (every 5 minutes)
3
- Documentation=https://github.com/writ/writ
2
+ Description=XSecurity firewall refresh timer (every 5 minutes)
3
+ Documentation=https://github.com/x-security/x-security
4
4
 
5
5
  [Timer]
6
6
  # Run shortly after boot, then every 5 minutes thereafter. AccuracySec
@@ -9,7 +9,7 @@ OnBootSec=30s
9
9
  OnUnitActiveSec=5min
10
10
  AccuracySec=30s
11
11
  Persistent=true
12
- Unit=writ-refresh.service
12
+ Unit=x-security-refresh.service
13
13
 
14
14
  [Install]
15
15
  WantedBy=timers.target
@@ -1,12 +1,12 @@
1
1
  #!/bin/sh
2
- # writ-resolve.sh — deploy-time DNS resolver for Writ firewall rules.
2
+ # x-security-resolve.sh — deploy-time DNS resolver for XSecurity firewall rules.
3
3
  #
4
- # Reads an iptables-save-format ruleset containing @@WRIT_RESOLVE:<fqdn>@@
4
+ # Reads an iptables-save-format ruleset containing @@X_SECURITY_RESOLVE:<fqdn>@@
5
5
  # tokens (produced by `lazy generate --target firewall`) and rewrites
6
6
  # each token into one or more concrete `-d <addr>` clauses by resolving the
7
7
  # FQDN against the host's system resolver.
8
8
  #
9
- # Generated by Writ — DO NOT EDIT in place. If you need to customize
9
+ # Generated by XSecurity — DO NOT EDIT in place. If you need to customize
10
10
  # behavior, override via the environment variables documented in the
11
11
  # accompanying README.md.
12
12
  #
@@ -27,8 +27,8 @@
27
27
  # via the provided logrotate.d snippet.
28
28
  #
29
29
  # Usage:
30
- # writ-resolve.sh [--rules-file PATH] [--out PATH] [--lenient]
31
- # ... | writ-resolve.sh > resolved.rules
30
+ # x-security-resolve.sh [--rules-file PATH] [--out PATH] [--lenient]
31
+ # ... | x-security-resolve.sh > resolved.rules
32
32
  #
33
33
  # Exit codes:
34
34
  # 0 success — all tokens resolved
@@ -38,7 +38,7 @@
38
38
 
39
39
  set -eu
40
40
 
41
- LOG_FILE="${WRIT_LOG:-/var/log/writ-resolve.log}"
41
+ LOG_FILE="${X_SECURITY_LOG:-/var/log/x-security-resolve.log}"
42
42
  LENIENT=0
43
43
  RULES_FILE=""
44
44
  OUT_FILE=""
@@ -52,7 +52,7 @@ log() {
52
52
 
53
53
  usage() {
54
54
  cat >&2 <<'EOF'
55
- writ-resolve.sh [--rules-file PATH] [--out PATH] [--lenient]
55
+ x-security-resolve.sh [--rules-file PATH] [--out PATH] [--lenient]
56
56
 
57
57
  --rules-file PATH Read template from PATH instead of stdin.
58
58
  --out PATH Write resolved ruleset to PATH instead of stdout.
@@ -60,7 +60,7 @@ writ-resolve.sh [--rules-file PATH] [--out PATH] [--lenient]
60
60
  Default is strict: any failed resolution => exit 1.
61
61
 
62
62
  Environment:
63
- WRIT_LOG Override log path (default /var/log/writ-resolve.log)
63
+ X_SECURITY_LOG Override log path (default /var/log/x-security-resolve.log)
64
64
  EOF
65
65
  }
66
66
 
@@ -102,14 +102,14 @@ else
102
102
  INPUT=$(cat)
103
103
  fi
104
104
 
105
- # Pass 1: extract every @@WRIT_RESOLVE:<fqdn>@@ token. Skip comment
105
+ # Pass 1: extract every @@X_SECURITY_RESOLVE:<fqdn>@@ token. Skip comment
106
106
  # lines (the generator's header documents the token format with a literal
107
- # `@@WRIT_RESOLVE:<fqdn>@@` example — we must not try to resolve
107
+ # `@@X_SECURITY_RESOLVE:<fqdn>@@` example — we must not try to resolve
108
108
  # `<fqdn>` as a real hostname).
109
109
  FQDNS=$(printf '%s\n' "$INPUT" \
110
110
  | grep -v '^[[:space:]]*#' \
111
- | grep -oE '@@WRIT_RESOLVE:[^@]+@@' \
112
- | sed -e 's/^@@WRIT_RESOLVE://' -e 's/@@$//' \
111
+ | grep -oE '@@X_SECURITY_RESOLVE:[^@]+@@' \
112
+ | sed -e 's/^@@X_SECURITY_RESOLVE://' -e 's/@@$//' \
113
113
  | sort -u)
114
114
 
115
115
  TOTAL=0
@@ -132,7 +132,7 @@ if [ -n "$FQDNS" ]; then
132
132
  addrs=$(resolve_fqdn "$fqdn" || true)
133
133
  if [ -z "$addrs" ]; then
134
134
  log "WARN: failed to resolve $fqdn"
135
- printf '%s\t__WRIT_UNRESOLVED__\n' "$fqdn" >> "$TMP_MAP"
135
+ printf '%s\t__X_SECURITY_UNRESOLVED__\n' "$fqdn" >> "$TMP_MAP"
136
136
  else
137
137
  log "INFO: resolved $fqdn -> $(echo "$addrs" | tr '\n' ' ')"
138
138
  echo "$addrs" | while IFS= read -r addr; do
@@ -148,7 +148,7 @@ fi
148
148
  # it with `|| echo 0` (that would emit two lines). Use a wc-based count and
149
149
  # always trim to a single integer.
150
150
  TOTAL=$(printf '%s\n' "$FQDNS" | grep -v '^$' | wc -l | tr -d ' \n')
151
- FAILED=$(grep -c '__WRIT_UNRESOLVED__' "$TMP_MAP" 2>/dev/null | head -n 1 | tr -d ' \n')
151
+ FAILED=$(grep -c '__X_SECURITY_UNRESOLVED__' "$TMP_MAP" 2>/dev/null | head -n 1 | tr -d ' \n')
152
152
  [ -z "$FAILED" ] && FAILED=0
153
153
  RESOLVED=$((TOTAL - FAILED))
154
154
 
@@ -162,7 +162,7 @@ if [ "$FAILED" -gt 0 ] && [ "$LENIENT" -eq 0 ]; then
162
162
  exit 1
163
163
  fi
164
164
 
165
- # Pass 2: substitute. For every line containing a @@WRIT_RESOLVE:X@@
165
+ # Pass 2: substitute. For every line containing a @@X_SECURITY_RESOLVE:X@@
166
166
  # token, emit one copy per resolved address (with `-d <addr>` replacing the
167
167
  # token). Lines for unresolved FQDNs are dropped (in lenient mode), which is
168
168
  # fail-closed: those destinations remain unreachable.
@@ -171,7 +171,7 @@ OUTPUT=$(printf '%s\n' "$INPUT" | awk -v mapfile="$TMP_MAP" '
171
171
  while ((getline line < mapfile) > 0) {
172
172
  n = split(line, f, "\t")
173
173
  if (n < 2) continue
174
- if (f[2] == "__WRIT_UNRESOLVED__") {
174
+ if (f[2] == "__X_SECURITY_UNRESOLVED__") {
175
175
  unresolved[f[1]] = 1
176
176
  continue
177
177
  }
@@ -190,10 +190,10 @@ OUTPUT=$(printf '%s\n' "$INPUT" | awk -v mapfile="$TMP_MAP" '
190
190
  close(mapfile)
191
191
  }
192
192
  {
193
- if (match($0, /@@WRIT_RESOLVE:[^@]+@@/)) {
193
+ if (match($0, /@@X_SECURITY_RESOLVE:[^@]+@@/)) {
194
194
  token = substr($0, RSTART, RLENGTH)
195
195
  fqdn = token
196
- sub(/^@@WRIT_RESOLVE:/, "", fqdn)
196
+ sub(/^@@X_SECURITY_RESOLVE:/, "", fqdn)
197
197
  sub(/@@$/, "", fqdn)
198
198
  if (fqdn in unresolved) {
199
199
  # Drop the rule — fail-closed.
@@ -203,7 +203,7 @@ OUTPUT=$(printf '%s\n' "$INPUT" | awk -v mapfile="$TMP_MAP" '
203
203
  m = split(addrs[fqdn], a, "\n")
204
204
  for (i = 1; i <= m; i++) {
205
205
  line = $0
206
- sub(/@@WRIT_RESOLVE:[^@]+@@/, "-d " a[i], line)
206
+ sub(/@@X_SECURITY_RESOLVE:[^@]+@@/, "-d " a[i], line)
207
207
  print line
208
208
  }
209
209
  next
@@ -1,6 +1,6 @@
1
- # /etc/logrotate.d/writ — sample logrotate config for Writ refresh log.
2
- # Copy to /etc/logrotate.d/writ and adjust paths/retention to taste.
3
- /var/log/writ-resolve.log {
1
+ # /etc/logrotate.d/x-security — sample logrotate config for XSecurity refresh log.
2
+ # Copy to /etc/logrotate.d/x-security and adjust paths/retention to taste.
3
+ /var/log/x-security-resolve.log {
4
4
  weekly
5
5
  rotate 8
6
6
  compress