Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ PastureStack is an independent community effort to preserve, audit, and moderniz

Earlier prerelease coordinates are retired from current release references;
their reviewed source commits remain in Git history. This source tree targets
the pure numeric coordinate `v0.3.8`; the GitHub tag and Release, rather than
the pure numeric coordinate `v0.3.9`; the GitHub tag and Release, rather than
this README, determine when it is published. Product identity is carried by
the repository, catalog metadata, and provenance rather than the version tag.

Expand Down Expand Up @@ -119,6 +119,12 @@ adapter for the per-host driver. Image digests and live upgrade evidence are
separate gates; neither package source tests nor one-host allocation prove the
encrypted two-host lifecycle.

Version `10` uses the published `v0.14.35` image and bounds the connectivity
sidecar's TCP 80 bind retry during a managed upgrade. It does not alter
firewall ownership or backend selection. The image digest is recorded in
`catalog-images.json`; live Catalog activation and two-host lifecycle remain
separate acceptance gates.

Deployable Compose files use semantic version tags only. A published version
tag must never be replaced. Manifest digests remain release-verification
evidence and are not inserted into Catalog, Compose, API, or user-interface
Expand Down
19 changes: 19 additions & 0 deletions catalog-images.json
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,25 @@
"secrets": 0
}
},
{
"reference": "ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.35",
"manifestDigest": "sha256:452405892045346614eac8e2680b1b715bf6df3913ea4435dbee3550b60c07bb",
"sourceRepository": "https://github.com/PastureStack/ipsec-vxlan-overlay-network",
"sourceCommit": "bf81eef04ae64fd94155595fde8be7581900f4a8",
"sourcePath": "package/Dockerfile",
"registryPage": "https://github.com/orgs/PastureStack/packages/container/package/ipsec-vxlan-overlay-network",
"licenseBoundary": "Apache-2.0 source and image; bundled Ubuntu, strongSwan, CNI, Weave, and other packages retain their upstream licenses and notices",
"reviewedAt": "2026-09-14",
"platforms": ["linux/amd64"],
"vulnerabilityScan": {
"scanner": "Trivy 0.74.0",
"reportCreatedAt": "2026-09-14",
"scope": "published runtime image",
"high": 0,
"critical": 0,
"secrets": 0
}
},
{
"reference": "ghcr.io/pasturestack/network-plugin-manager:v0.6.34",
"sourceRepository": "https://github.com/PastureStack/network-plugin-manager",
Expand Down
33 changes: 33 additions & 0 deletions infra-templates/ipsec-overlay/10/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!-- SPDX-License-Identifier: MIT -->

# PastureStack IPsec Overlay 0.3.8

This infrastructure template is a candidate for the IPsec overlay data plane on every eligible host. A network-holder service owns the managed namespace, the router applies host XFRM and route state, the connectivity sidecar exposes the control-plane health contract, and the CNI sidecar supplies the bridge and address-management executables.

## Candidate template — published image

- Image: `ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.35` is recorded with its published manifest digest in `catalog-images.json`. The GitHub Release itself is not immutable.
- Version `10` gives the connectivity-check sidecar a bounded TCP 80 handoff during rolling upgrades. It waits only when the prior sidecar still owns its listener and fails clearly after 90 seconds or on another bind error; firewall rules and router port 8111 remain under their existing owners. Version `9` remains available for existing stacks.
- Version `9` updates the bundled CNI host-label adapter to the control plane's plain-text `/self/host/labels/<key>` contract. This lets per-host subnet workloads receive the host-specific bridge and IPAM ranges instead of failing CNI setup. Version `8` remains available for existing stacks.
- Version `8` retains the port-8111 handoff and peer-retry behavior. It lets the IPsec module, rather than strongSwan's CHILD close action, own missing-SA recovery. After a quiet period it removes only a zero-traffic established duplicate when one other installed SA for the same managed peer has traffic; ambiguous pairs remain untouched. Version `7` remains available for existing stacks but did not converge after a live rolling upgrade.
- Source license: Apache-2.0; Ubuntu, strongSwan, CNI, Weave, and bundled dependencies retain their upstream licenses and notices.

## Privilege and secret boundary

The router is privileged and uses host PID and network namespaces. In all three firewall backends it synchronizes IPsec XFRM state and routes, but does not write host firewall chains. Network Plugin Manager alone owns the overlay bridge-subnet forward mark, NAT exclusion, and host-port rules. The router does not create a second nftables mark table, patch the manager's `CATTLE_*` chains, or change Docker's tables. The router receives a read-only Docker socket mount to query the actual firewall driver; Unix socket access still grants a powerful Docker API capability, so it remains confined to this trusted privileged system service. The CNI sidecar also accesses the Docker socket. These permissions are required by this compatibility architecture and must not be copied to ordinary workloads.

The router receives a scoped create-agent credential from the compatible control plane and downloads the generated IPsec pre-shared key through the authenticated `configcontent/psk` contract. This template does not accept a user-supplied key and never places a key in the public Catalog repository, Compose variables, image, or logs.

## Compatibility boundary

The literal `rancher-compose.yml` filename, `minimum_rancher_version` key, required `io.rancher.*` orchestration labels, `rancher-cni-driver` shared volume, and `ipsec` agent-service marker are consumed by the compatible control plane and network plugin manager. They are protocol identifiers, not PastureStack branding. User-facing names, image coordinates, commands, environment variables, CNI names, log paths, and the `pasture.internal` search suffix use current PastureStack identifiers.

The data plane currently supports the compatibility network `10.42.0.0/16`; the template intentionally does not expose a subnet selector that the runtime cannot safely honor.

The host firewall backend is selected explicitly or left at `auto`. The four supported choices are `auto`, native `nftables`, `iptables-nft`, and `iptables-legacy`. The selection is passed only to `overlay-router` through `PASTURESTACK_FIREWALL_BACKEND`. The router checks Docker's actual driver and live rule owner, not the Ubuntu version: even on Ubuntu 26.04 and later, an existing `iptables-legacy` or `iptables-nft` deployment keeps that active path. An explicit mismatch or ambiguous state fails safely without switching backends or activating unloaded legacy modules. Align the choice with the Network Services template on the same environment.

The Native project definition lists Network Services before IPsec, but list order alone does not establish a health dependency. Before creating or upgrading this overlay, apply the matching Network Services version and wait until Network Plugin Manager is healthy on every target host. In native `nftables` mode, first satisfy that template's Docker firewall-backend, bridge-accept-fwmark, and persistent IPv4-forwarding prerequisites; an IPsec router alone cannot provide the manager-owned forwarding and NAT rules.

## Release boundary

The published `v0.14.35` image is recorded with its real manifest digest. The isolated native nftables, iptables-nft, and iptables-legacy gates must remain green. Managed upgrade and peer-restart evidence must be checked separately; a successful CNI address allocation alone does not prove the encrypted multi-host lifecycle.
79 changes: 79 additions & 0 deletions infra-templates/ipsec-overlay/10/README.zh-TW.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<!-- SPDX-License-Identifier: MIT -->

# PastureStack IPsec 加密網路 0.3.8

此候選基礎架構範本預計在每台符合條件的主機上安裝 IPsec 加密
網路資料平面。網路持有服務負責受管命名空間;路由器套用主機 XFRM
與路由狀態;連線檢查相關容器提供控制平面健康狀態契約;CNI 相關
容器則提供網橋與位址管理執行檔。

## 候選範本:映像已發布

- 映像 `ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.35` 已正式發布;
真實 manifest digest、來源 revision 與執行映像安全掃描已記錄於
`catalog-images.json`。GitHub Release 並未標示為不可變。
- 第 `10` 版在滾動升級時,若舊版連線檢查容器尚占用 TCP 80,
新版只對此埠占用情況等待,最多 90 秒;其他監聽錯誤或逾時仍會
明確失敗。此處不更動防火牆規則或路由器的 8111 連接埠責任。
第 `9` 版仍供既有堆疊使用。
- 第 `8` 版保留對等主機重試與 8111 連接埠交接。IPsec 模組統一負責
缺失 SA 的重建;超過觀察期間且同一對等主機恰有一條已使用的健康
SA 時,才清除另一條零流量的重複 SA。無法明確判斷的連線不動。
第 `7` 版仍供既有堆疊參照,但真機滾動升級後曾留下兩條已建立 SA。
- 第 `9` 版將隨附 CNI 的主機標籤查詢改為控制平面實際提供的純文字
`/self/host/labels/<key>` 契約,讓每主機子網路可正確取得網橋與 IPAM
位址範圍。第 `8` 版仍供既有堆疊使用。
- 原始碼採 Apache-2.0 授權;Ubuntu、strongSwan、CNI、Weave 與
隨附相依套件保留各自的上游授權及聲明。

## 權限與機密資料界線

路由器使用特權模式並加入主機 PID 與網路命名空間。在三種防火牆
後端,它只同步 IPsec XFRM 狀態與路由,不寫入主機防火牆規則。
網路外掛管理器獨自維護 overlay 網橋子網路的轉送標記、NAT 排除及
主機連接埠規則。路由器不另建 nftables 標記表、不修改管理器的
`CATTLE_*` 規則鏈,也不修改 Docker 的規則表。路由器以唯讀掛載 Docker Socket 查詢
實際防火牆驅動程式;唯讀掛載仍賦予強大的 Docker API 存取能力,
只限此受信任的特權系統服務使用。CNI 相關容器也存取 Docker Socket。
這些權限是相容架構所需,
不得套用到一般工作負載。

路由器會從相容控制平面取得範圍受限的代理程式登入資訊,再透過已驗證
的 `configcontent/psk` 契約下載 IPsec 預先共用金鑰。此範本不接受
使用者提供的金鑰,也不會把金鑰放入公開商店、Compose 變數、映像或
日誌。

## 相容性界線

`rancher-compose.yml`、`minimum_rancher_version`、必要的
`io.rancher.*` 編排標籤、`rancher-cni-driver` 共用磁碟區及
`ipsec` 代理程式服務標記是相容控制平面與網路外掛管理器使用的協定
識別名稱。使用者可見名稱、映像位置、命令、環境變數、CNI 名稱、
日誌路徑及 `pasture.internal` 搜尋後綴均採用 PastureStack 名稱。

資料平面目前支援 `10.42.0.0/16` 相容網路。執行環境無法安全套用
任意子網路,因此範本不提供無效的子網路選項。

主機防火牆後端可選 `auto`、原生 `nftables`、`iptables-nft` 或
`iptables-legacy`。選擇會透過 `PASTURESTACK_FIREWALL_BACKEND` 傳給
`overlay-router`。路由器檢查 Docker 實際驅動程式與現役規則擁有者,
不以 Ubuntu 版本推斷;Ubuntu 26.04 及更新版若已使用 `iptables-legacy`
或 `iptables-nft`,仍維持該現役路徑。明確指定與實際後端不符或狀態
無法判定時安全停止,不切換後端,也不載入尚未啟用的 legacy 模組。
同環境的 Network Services 範本應使用一致的選項。

Native 專案定義將 Network Services 排在 IPsec 前面,但清單順序
本身不保證健康狀態相依。建立或升級加密網路前,應先套用相符版本
的 Network Services,等待每台目標主機上的網路外掛管理器恢復
健康。使用原生 `nftables` 時,須先完成該範本列出的 Docker
防火牆後端、`bridge-accept-fwmark` 與持久 IPv4 轉送前置設定;
只有 IPsec 路由器無法提供管理器負責的轉送及 NAT 規則。

## 發布界線

已發布的 `v0.14.35` 映像已記錄真實 manifest digest。原生 nftables、
iptables-nft 與 iptables-legacy 的隔離驗收必須保持通過;受管升級及
對等主機重啟還須確認暫時離線的主機不會拆掉其他健康連線、同一對等
主機收斂為一條可用 IKE SA,新路由器
仍等待 8111 埠釋放,且不越界修改網路外掛管理器的防火牆規則。
本版實機結果須另行記錄;單純完成 CNI 位址分配不能代替加密跨主機生命週期驗收。
114 changes: 114 additions & 0 deletions infra-templates/ipsec-overlay/10/docker-compose.yml.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# SPDX-License-Identifier: MIT
version: '2'

services:
overlay-network:
image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.35
command:
- /bin/bash
- -c
- 'mkfifo /tmp/overlay-log; exec cat /tmp/overlay-log'
network_mode: ipsec
labels:
io.pasturestack.component: ipsec-overlay
io.rancher.sidekicks: overlay-router,connectivity-check
io.rancher.scheduler.global: 'true'
io.rancher.cni.link_mtu_overhead: '0'
io.rancher.network.macsync: 'true'
io.rancher.network.arpsync: 'true'

overlay-router:
image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.35
command: start-ipsec.sh
privileged: true
network_mode: container:overlay-network
pid: host
environment:
PASTURESTACK_DEBUG: '${PASTURESTACK_DEBUG}'
PASTURESTACK_FIREWALL_BACKEND: '${FIREWALL_BACKEND}'
PASTURESTACK_NETWORK_XFRM_NETNS_PATH: /proc/1/ns/net
PASTURESTACK_NETWORK_XFRM_TUNNEL_SOURCE: host
PASTURESTACK_NETWORK_RUN_IN_HOST_NETNS: 'true'
PASTURESTACK_NETWORK_ARP_INTERFACE: '${DOCKER_BRIDGE}'
PASTURESTACK_NETWORK_SYNC_HOST_ROUTES: 'true'
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
labels:
io.pasturestack.component: ipsec-overlay-router
io.rancher.container.create_agent: 'true'
io.rancher.container.agent_service.ipsec: 'true'
logging:
driver: json-file
options:
max-size: 25m
max-file: '2'
sysctls:
net.ipv4.conf.all.send_redirects: '0'
net.ipv4.conf.default.send_redirects: '0'

connectivity-check:
image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.35
command:
- ipsec-vxlan-connectivity-check
- --connectivity-check-interval
- '${CONNECTIVITY_CHECK_INTERVAL}'
- --peer-connection-timeout
- '${PEER_CONNECTION_TIMEOUT}'
network_mode: container:overlay-network
environment:
PASTURESTACK_DEBUG: '${PASTURESTACK_DEBUG}'
PASTURESTACK_METADATA_ADDRESS: 169.254.169.250
labels:
io.pasturestack.component: ipsec-overlay-connectivity

cni-driver:
image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.35
command: start-cni-driver.sh
privileged: true
network_mode: host
pid: host
environment:
PASTURESTACK_DEBUG: '${PASTURESTACK_DEBUG}'
labels:
io.pasturestack.component: ipsec-overlay-cni
io.rancher.scheduler.global: 'true'
io.rancher.network.cni.binary: pasture-bridge
io.rancher.container.dns: 'true'
logging:
driver: json-file
options:
max-size: 25m
max-file: '2'
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- rancher-cni-driver:/opt/cni-driver
network_driver:
name: PastureStack IPsec Overlay
default_network:
name: ipsec
host_ports: {{ .Values.HOST_PORTS }}
subnets:
- network_address: 10.42.0.0/16
dns:
- 169.254.169.250
dns_search:
- pasture.internal
cni_config:
'10-pasturestack.conf':
name: pasturestack-cni-network
type: pasture-bridge
bridge: $DOCKER_BRIDGE
bridgeSubnet: 10.42.0.0/16
logToFile: /var/log/pasturestack-cni.log
isDebugLevel: ${PASTURESTACK_DEBUG}
isDefaultGateway: true
hostNat: true
hairpinMode: {{ .Values.PASTURESTACK_HAIRPIN_MODE }}
promiscMode: {{ .Values.PASTURESTACK_PROMISCUOUS_MODE }}
mtu: ${MTU}
linkMTUOverhead: 98
ipam:
type: metadata-cni-ipam
subnetPrefixSize: /16
logToFile: /var/log/pasturestack-cni.log
isDebugLevel: ${PASTURESTACK_DEBUG}
Loading