From 3b30101c1f00bf5d6b426ed0c82c0a82c12aebba Mon Sep 17 00:00:00 2001 From: chen21019 <19357113+chen21019@users.noreply.github.com> Date: Fri, 23 Oct 2026 19:55:43 +0800 Subject: [PATCH 01/10] build: refresh Python security tools for catalog 0.3.14 --- .github/workflows/validate.yml | 9 +++++---- .python-version | 2 +- README.md | 8 +++++--- integration/requirements.lock | 4 ++++ 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index f7e12f1e8..eb1de762b 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -32,7 +32,7 @@ jobs: - name: Set up pinned Python toolchain uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: - python-version: '3.14.6' + python-version: '3.14.9' check-latest: false - name: Validate images, schema, and localized metadata @@ -57,14 +57,15 @@ jobs: } trap cleanup EXIT - test "$(cat .python-version)" = '3.14.6' + test "$(cat .python-version)" = '3.14.9' test "$(python -c 'import platform; print(platform.python_version())')" = \ - '3.14.6' + '3.14.9' python -m pip install \ --disable-pip-version-check \ --require-hashes \ --only-binary=:all: \ --requirement integration/requirements.lock + python -c "import pip, certifi, pip._vendor.certifi as bundled; assert pip.__version__ == '26.2.2'; assert certifi.__version__ == '2026.10.19'; assert bundled.__version__ == '2026.10.19'; print(pip.__version__, certifi.__version__, bundled.__version__)" python -m flake8 integration/core bash scripts/audit-deployable-images @@ -243,7 +244,7 @@ jobs: python -m pytest -q integration/core \ -k 'not test_validate_exits_normal' - echo "CATALOG_TW_LOCALIZATION_OK source=$SOURCE_SHA templates=22 infra_first_party=21 python=3.14.6" + echo "CATALOG_TW_LOCALIZATION_OK source=$SOURCE_SHA templates=22 infra_first_party=21 python=3.14.9" release: if: github.event_name == 'push' && github.ref_type == 'tag' diff --git a/.python-version b/.python-version index 3f0a10fda..70c445ec1 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.14.6 +3.14.9 diff --git a/README.md b/README.md index 22aa1c43e..de2de9121 100644 --- a/README.md +++ b/README.md @@ -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.13`; the GitHub tag and Release, rather than +the pure numeric coordinate `v0.3.14`; 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. @@ -179,8 +179,10 @@ 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 image references. No automatic deployment or publishing trigger is enabled. -The manually dispatched compatibility workflow uses Python `3.14.6`, verifies -every Python dependency against its PyPI SHA-256, and runs flake8, pytest, the +The manually dispatched compatibility workflow uses Python `3.14.9`, verifies +every Python dependency against its PyPI SHA-256, including pip `26.2.2` and +certifi `2026.10.19`. It reads back both external and pip-bundled certifi and +runs flake8, pytest, the Catalog audit, and Catalog Service API gates against the exact selected commit. GitHub CodeQL independently scans the Actions and Python sources. A Server release pins the Catalog only after those gates pass; none of these checks is a diff --git a/integration/requirements.lock b/integration/requirements.lock index 160abeaf6..30f52d5fa 100644 --- a/integration/requirements.lock +++ b/integration/requirements.lock @@ -1,3 +1,7 @@ +pip==26.2.2 \ + --hash=sha256:fd7f4dfa8190e014013b9f08f3e973f4e4c26ffd179a204895533a7254813a70 +certifi==2026.10.19 \ + --hash=sha256:42d35340cc5b9ba78e818ddbff0c5b1c2b779de448a340fd1b989f5fa8670e1b flake8==7.3.0 \ --hash=sha256:b9696257b9ce8beb888cdbe31cf885c90d31928fe202be0889a7cdafad32f01e \ --hash=sha256:fe044858146b9fc69b551a4b490d69cf960fcb78ad1edcb84e7fbb1b4a8e3872 From 0fa86d9456c6317ad0f2b27e696c055d189d27a4 Mon Sep 17 00:00:00 2001 From: chen21019 <19357113+chen21019@users.noreply.github.com> Date: Fri, 23 Oct 2026 20:57:28 +0800 Subject: [PATCH 02/10] build: consume frozen pip security rebuild and catalog service release --- .github/workflows/validate.yml | 15 +- README.md | 10 +- integration/requirements.lock | 4 +- .../pip-security-overlay/build-pip-overlay.py | 197 ++++++++++++++++++ tools/pip-security-overlay/inputs.json | 188 +++++++++++++++++ .../pip-security-overlay/test-pip-overlay.py | 143 +++++++++++++ 6 files changed, 550 insertions(+), 7 deletions(-) create mode 100644 tools/pip-security-overlay/build-pip-overlay.py create mode 100644 tools/pip-security-overlay/inputs.json create mode 100644 tools/pip-security-overlay/test-pip-overlay.py diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index eb1de762b..5f3718e5f 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -37,8 +37,8 @@ jobs: - name: Validate images, schema, and localized metadata env: - CATALOG_SERVICE_VERSION: 0.20.11 - CATALOG_SERVICE_SHA256: b44bc4d337ea3b54d5a5febca2060ce23e3b988c298c2fb926227fea3c228d3d + CATALOG_SERVICE_VERSION: 0.20.15 + CATALOG_SERVICE_SHA256: 7c059101265d897e4b176f503a9217b112946d37d91daa0c40f421fb16e4bb6b PASTURESTACK_CATALOG_ALLOWED_LOCAL_ROOTS: /tmp TMPDIR: /tmp SOURCE_SHA: ${{ github.sha }} @@ -60,12 +60,21 @@ jobs: test "$(cat .python-version)" = '3.14.9' test "$(python -c 'import platform; print(platform.python_version())')" = \ '3.14.9' + python tools/pip-security-overlay/build-pip-overlay.py \ + --work "$work_root/pip-build" --output "$work_root/pip-dist" + python -m venv --without-pip "$work_root/python-env" + export PATH="$work_root/python-env/bin:$PATH" + PYTHONPATH="$work_root/pip-dist/pip-26.2.2+pasturestack.1-py3-none-any.whl" \ + python -m pip install --no-index --no-deps \ + "$work_root/pip-dist/pip-26.2.2+pasturestack.1-py3-none-any.whl" python -m pip install \ --disable-pip-version-check \ --require-hashes \ --only-binary=:all: \ + --find-links "$work_root/pip-dist" \ --requirement integration/requirements.lock - python -c "import pip, certifi, pip._vendor.certifi as bundled; assert pip.__version__ == '26.2.2'; assert certifi.__version__ == '2026.10.19'; assert bundled.__version__ == '2026.10.19'; print(pip.__version__, certifi.__version__, bundled.__version__)" + python -c "import pip, certifi, pip._vendor.certifi as bundled; assert pip.__version__ == '26.2.2+pasturestack.1'; assert certifi.__version__ == '2026.10.19'; assert bundled.__version__ == '2026.10.19'; print(pip.__version__, certifi.__version__, bundled.__version__)" + python tools/pip-security-overlay/test-pip-overlay.py python -m flake8 integration/core bash scripts/audit-deployable-images diff --git a/README.md b/README.md index de2de9121..8ac50d937 100644 --- a/README.md +++ b/README.md @@ -180,8 +180,14 @@ tag must never be replaced. Manifest digests remain release-verification evidence and are not inserted into Catalog, Compose, API, or user-interface image references. No automatic deployment or publishing trigger is enabled. The manually dispatched compatibility workflow uses Python `3.14.9`, verifies -every Python dependency against its PyPI SHA-256, including pip `26.2.2` and -certifi `2026.10.19`. It reads back both external and pip-bundled certifi and +every Python dependency against its SHA-256, including the explicitly internal +pip `26.2.2+pasturestack.1` rebuild and official certifi `2026.10.19`. +The frozen shared helper rebuilds official pip source with upstream vendoring, +changing only released urllib3 to `2.8.0`; all inputs, licenses, RECORD hashes, +and the resulting wheel SHA-256 are verified. CI uses an isolated environment, +checks streaming regression and trusted/untrusted TLS behavior, and never +modifies the runner's global Python installation. +It reads back both external and pip-bundled certifi and runs flake8, pytest, the Catalog audit, and Catalog Service API gates against the exact selected commit. GitHub CodeQL independently scans the Actions and Python sources. A Server diff --git a/integration/requirements.lock b/integration/requirements.lock index 30f52d5fa..52c84668e 100644 --- a/integration/requirements.lock +++ b/integration/requirements.lock @@ -1,5 +1,5 @@ -pip==26.2.2 \ - --hash=sha256:fd7f4dfa8190e014013b9f08f3e973f4e4c26ffd179a204895533a7254813a70 +pip==26.2.2+pasturestack.1 \ + --hash=sha256:be5f63d537bbe611dc422fabb6740a44b5997888b592888df5091727f023802a certifi==2026.10.19 \ --hash=sha256:42d35340cc5b9ba78e818ddbff0c5b1c2b779de448a340fd1b989f5fa8670e1b flake8==7.3.0 \ diff --git a/tools/pip-security-overlay/build-pip-overlay.py b/tools/pip-security-overlay/build-pip-overlay.py new file mode 100644 index 000000000..88b53806c --- /dev/null +++ b/tools/pip-security-overlay/build-pip-overlay.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python3 +"""Rebuild pip using released urllib3 and pip's unmodified vendoring machinery. + +Build dependencies never enter the product wheel. All network inputs are HTTPS +and SHA-256 pinned. The resulting local version is not an official pip release. +""" +import argparse +import base64 +import csv +import hashlib +import io +import json +import os +from pathlib import Path +import shutil +import subprocess +import sys +import tarfile +import tempfile +from urllib.request import HTTPRedirectHandler, HTTPSHandler, build_opener +from urllib.parse import urlsplit +import venv +import zipfile + + +class HTTPSOnlyRedirect(HTTPRedirectHandler): + def redirect_request(self, req, fp, code, msg, headers, newurl): + if urlsplit(newurl).scheme != "https": + raise ValueError("Refusing a non-HTTPS build-input redirect") + return super().redirect_request(req, fp, code, msg, headers, newurl) + + +def sha(path): + return hashlib.sha256(path.read_bytes()).hexdigest() + + +def run(command, cwd, env): + print("+", " ".join(map(str, command)), flush=True) + subprocess.run(list(map(str, command)), cwd=cwd, env=env, check=True) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--output", type=Path, required=True) + parser.add_argument("--work", type=Path, required=True) + parser.add_argument("--input-cache", type=Path) + parser.add_argument("--offline", action="store_true") + args = parser.parse_args() + output, work = args.output.resolve(), args.work.resolve() + output.mkdir(parents=True, exist_ok=True) + work.mkdir(parents=True, exist_ok=True) + config = json.loads(Path(__file__).with_name("inputs.json").read_text()) + assert sys.version_info[:2] in ((3, 12), (3, 14)) and os.name == "posix" + scratch = Path(tempfile.mkdtemp(prefix="pip-revendor-", dir=work)) + downloads = scratch / "downloads" + downloads.mkdir() + cache = args.input_cache.resolve() if args.input_cache else downloads + cache.mkdir(parents=True, exist_ok=True) + paths = {} + for item in config["artifacts"]: + assert urlsplit(item["url"]).scheme == "https" + target = downloads / Path(urlsplit(item["url"]).path).name + cached = cache / target.name + if not cached.is_file(): + assert not args.offline, ("Offline input is missing", target.name) + opener = build_opener(HTTPSHandler(), HTTPSOnlyRedirect()) + with opener.open(item["url"], timeout=90) as response, cached.open("wb") as dest: + shutil.copyfileobj(response, dest) + assert sha(cached) == item["sha256"], ("cached input hash mismatch", target.name) + if cached != target: + shutil.copy2(cached, target) + assert sha(target) == item["sha256"], ("input hash mismatch", target.name) + paths.setdefault(item["name"], []).append(target) + + environment = os.environ.copy() + environment.update(PIP_NO_INDEX="1", PIP_FIND_LINKS=str(downloads), + PIP_DISABLE_PIP_VERSION_CHECK="1", PIP_ONLY_BINARY=":all:", + PYTHONHASHSEED="0", SOURCE_DATE_EPOCH=str(config["sourceDateEpoch"])) + for key in ("PYTHONPATH", "PYTHONHOME", "PIP_INDEX_URL", "PIP_EXTRA_INDEX_URL", + "PIP_TRUSTED_HOST", "PIP_CERT", "PIP_CLIENT_CERT"): + environment.pop(key, None) + environment["PIP_CONFIG_FILE"] = os.devnull + tool_env = scratch / "tool-env" + venv.EnvBuilder(with_pip=False).create(tool_env) + python = tool_env / "bin/python" + requirements = scratch / "tools.lock" + groups = {} + for item in config["artifacts"]: + if item["kind"] == "tool": + groups.setdefault((item["name"], item["version"]), []).append(item["sha256"]) + requirements.write_text("\n".join( + f"{name}=={version} " + " ".join(f"--hash=sha256:{value}" for value in hashes) + for (name, version), hashes in sorted(groups.items())) + "\n") + bootstrap_env = dict(environment, PYTHONPATH=str(paths["pip"][0])) + run([python, "-m", "pip", "install", "--require-hashes", "--no-compile", "-r", requirements], scratch, bootstrap_env) + environment["PATH"] = str(tool_env / "bin") + os.pathsep + environment["PATH"] + + source_parent = scratch / "source" + source_parent.mkdir() + with tarfile.open(paths["pip-source"][0]) as archive: + # Reject links and traversal before extracting this fixed official archive. + for member in archive.getmembers(): + assert not member.issym() and not member.islnk() + resolved = (source_parent / member.name).resolve() + assert resolved.is_relative_to(source_parent) + archive.extractall(source_parent, filter="data") + source = next(source_parent.iterdir()) + vendor = source / "src/pip/_vendor" + original = {str(p.relative_to(vendor)): sha(p) for p in vendor.rglob("*") if p.is_file()} + assert (source / "src/pip/__init__.py").read_text().count('__version__ = "26.2.2"') == 1 + + # A scoped project invokes the same upstream tool, namespace and urllib3 + # patches. Unrelated vendored libraries are never regenerated or replaced. + scoped = scratch / "urllib3-vendoring" + scoped_vendor = scoped / "src/pip/_vendor" + scoped_vendor.mkdir(parents=True) + (scoped_vendor / "vendor.txt").write_text("urllib3==2.8.0\n") + patches = scoped / "tools/vendoring/patches" + patches.mkdir(parents=True) + for patch in (source / "tools/vendoring/patches").glob("urllib3*.patch"): + shutil.copy2(patch, patches / patch.name) + assert len(list(patches.glob("*.patch"))) == 3 + (scoped / "pyproject.toml").write_text('''[tool.vendoring] +destination = "src/pip/_vendor/" +requirements = "src/pip/_vendor/vendor.txt" +namespace = "pip._vendor" +protected-files = ["vendor.txt"] +patches-dir = "tools/vendoring/patches" +[tool.vendoring.transformations] +drop = ["*.dist-info/", "bin/"] +''') + run([python, "-m", "vendoring", "sync", "-v"], scoped, environment) + generated = scoped_vendor / "urllib3" + assert (generated / "__init__.py").is_file() + shutil.rmtree(vendor / "urllib3") # exact disposable source subtree only + shutil.copytree(generated, vendor / "urllib3") + vendor_txt = vendor / "vendor.txt" + text = vendor_txt.read_text() + assert text.count("urllib3==2.7.0") == 1 + vendor_txt.write_text(text.replace("urllib3==2.7.0", "urllib3==2.8.0")) + version_file = source / "src/pip/__init__.py" + version_file.write_text(version_file.read_text().replace('__version__ = "26.2.2"', + f'__version__ = "{config["version"]}"')) + readme = vendor / "README.rst" + with readme.open("a") as handle: + handle.write("\n\nPastureStack security rebuild\n============================\n\n" + "This downstream local-version wheel uses released urllib3 2.8.0\n" + "through upstream vendoring 1.4.0 and pip's unchanged urllib3\n" + "patches. Other vendored library sources and licenses are unchanged.\n" + "It is not an official PyPA pip release.\n") + run([python, "-c", "from pathlib import Path; from vendoring.sbom import create_sbom_file; create_sbom_file('pip._vendor', Path('src/pip/_vendor/vendor.txt'), Path('src/pip/_vendor/bom.cdx.json'))"], source, environment) + current = {str(p.relative_to(vendor)): sha(p) for p in vendor.rglob("*") if p.is_file()} + allowed = {"vendor.txt", "README.rst", "bom.cdx.json"} + assert {p: value for p, value in original.items() if not p.startswith("urllib3/") and p not in allowed} == { + p: value for p, value in current.items() if not p.startswith("urllib3/") and p not in allowed} + wheels = [] + for suffix in ("first", "second"): + directory = scratch / suffix + directory.mkdir() + run([python, "-c", f"from flit_core.buildapi import build_wheel; build_wheel({str(directory)!r})"], source, environment) + wheels.append(next(directory.glob("*.whl"))) + assert sha(wheels[0]) == sha(wheels[1]), "wheel rebuild is not byte reproducible" + assert sha(wheels[0]) == config["expectedWheelSha256"], "unexpected rebuilt product bytes" + wheel = output / wheels[0].name + shutil.copy2(wheels[0], wheel) + licenses = [] + with zipfile.ZipFile(wheel) as archive: + names = archive.namelist() + record = next(name for name in names if name.endswith(".dist-info/RECORD")) + for name, digest, size in csv.reader(io.StringIO(archive.read(record).decode())): + if not digest: + assert name == record + continue + data = archive.read(name) + expected = "sha256=" + base64.urlsafe_b64encode(hashlib.sha256(data).digest()).rstrip(b"=").decode() + assert digest == expected and int(size) == len(data), name + assert not any(name.endswith((".so", ".pyd")) for name in names) + licenses = [name for name in names if "LICENSE" in name or "COPYING" in name] + assert any("urllib3" in name for name in licenses) + assert "pip/_vendor/pkg_resources/__init__.py" in names + assert not any("setuptools/package_index" in name for name in names) + shutil.copy2(vendor / "bom.cdx.json", output / "pip-vendor.cdx.json") + report = {"version": config["version"], "upstreamVersion": config["upstreamVersion"], + "upstreamCommit": config["sourceCommit"], "wheel": wheel.name, + "sha256": sha(wheel), "twoBuildsByteIdentical": True, + "allRecordHashesVerified": True, "nativeExtensionsPresent": False, + "licenses": licenses, "onlyVendoredLibraryChanged": "urllib3", "urllib3": "2.8.0"} + (output / "build-evidence.json").write_text(json.dumps(report, indent=2) + "\n") + shutil.copy2(requirements, output / "tools.lock") + shutil.copy2(Path(__file__).with_name("inputs.json"), output / "inputs.json") + print(json.dumps(report), flush=True) + + +if __name__ == "__main__": + if sys.flags.optimize: + raise RuntimeError("Security build verification must not run with Python optimization") + main() diff --git a/tools/pip-security-overlay/inputs.json b/tools/pip-security-overlay/inputs.json new file mode 100644 index 000000000..fc6b7de90 --- /dev/null +++ b/tools/pip-security-overlay/inputs.json @@ -0,0 +1,188 @@ +{ + "schemaVersion": 1, + "upstreamVersion": "26.2.2", + "version": "26.2.2+pasturestack.1", + "expectedWheelSha256": "be5f63d537bbe611dc422fabb6740a44b5997888b592888df5091727f023802a", + "sourceCommit": "b3b696fe2122f2339d782517559bfade2cb6b879", + "sourceDateEpoch": 1792509744, + "updatedVendoredLibraries": { + "urllib3": "2.8.0" + }, + "artifacts": [ + { + "kind": "tool", + "name": "vendoring", + "version": "1.4.0", + "url": "https://files.pythonhosted.org/packages/e3/ba/2fe43514bcf426888101c2968f3c821c6338afc122ccbbde6e29ee2a5036/vendoring-1.4.0-py3-none-any.whl", + "sha256": "3a5b5c44bdec2683a94cd4c7c25bad556b38539cf316defca65948d76107eb30" + }, + { + "kind": "tool", + "name": "flit_core", + "version": "3.12.0", + "url": "https://files.pythonhosted.org/packages/f2/65/b6ba90634c984a4fcc02c7e3afe523fef500c4980fec67cc27536ee50acf/flit_core-3.12.0-py3-none-any.whl", + "sha256": "e7a0304069ea895172e3c7bb703292e992c5d1555dd1233ab7b5621b5b69e62c" + }, + { + "kind": "tool", + "name": "click", + "version": "8.5.0", + "url": "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl", + "sha256": "255bc9599cf7748b4b1a446ccc735421bd08a2ae529a8b88597d3de5664ee360" + }, + { + "kind": "tool", + "name": "jsonschema", + "version": "4.26.0", + "url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", + "sha256": "d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce" + }, + { + "kind": "tool", + "name": "packaging", + "version": "26.3", + "url": "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", + "sha256": "d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c" + }, + { + "kind": "tool", + "name": "requests", + "version": "2.34.2", + "url": "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", + "sha256": "2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0" + }, + { + "kind": "tool", + "name": "rich", + "version": "15.0.0", + "url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", + "sha256": "33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb" + }, + { + "kind": "tool", + "name": "attrs", + "version": "26.1.0", + "url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", + "sha256": "c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309" + }, + { + "kind": "tool", + "name": "idna", + "version": "3.20", + "url": "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl", + "sha256": "ab7ae7122974553370f0bdb919e1a960b2cd1bc1ef0276416d896db81c14582c" + }, + { + "kind": "tool", + "name": "jsonschema-specifications", + "version": "2025.9.1", + "url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", + "sha256": "98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe" + }, + { + "kind": "tool", + "name": "markdown-it-py", + "version": "4.2.0", + "url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", + "sha256": "9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a" + }, + { + "kind": "tool", + "name": "Pygments", + "version": "2.21.0", + "url": "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl", + "sha256": "2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9" + }, + { + "kind": "tool", + "name": "referencing", + "version": "0.37.0", + "url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", + "sha256": "381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231" + }, + { + "kind": "tool", + "name": "urllib3", + "version": "2.8.0", + "url": "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl", + "sha256": "0cf3cae568d36aa9576b28dfb35f11328f1cb974ca7647d9475ebb86c75ac6e3" + }, + { + "kind": "tool", + "name": "mdurl", + "version": "0.1.2", + "url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", + "sha256": "84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8" + }, + { + "kind": "tool", + "name": "typing_extensions", + "version": "4.16.0", + "url": "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", + "sha256": "481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8" + }, + { + "kind": "tool", + "name": "tomli", + "version": "2.5.0", + "url": "https://files.pythonhosted.org/packages/60/3f/3e3f8fd0919249b0200c80fbc4f9a1e70be19f9883da71dfb7f8b9ab8aca/tomli-2.5.0-py3-none-any.whl", + "sha256": "32a7b79ac57a2e83670ce329ccf675798bc5a2094783a63676866b70503f2e2b" + }, + { + "kind": "tool", + "name": "charset-normalizer", + "version": "3.5.2", + "url": "https://files.pythonhosted.org/packages/fc/ad/d07d7862a62ffa6d79d68074d14823243dd235a77c45262acbf6adeb28bf/charset_normalizer-3.5.2-py3-none-any.whl", + "sha256": "b6b751274acb69d77b3323d6b7dbaa3c7fdfc1eb829b7eb61d262f32e1af9685" + }, + { + "kind": "tool", + "name": "certifi", + "version": "2026.10.19", + "url": "https://files.pythonhosted.org/packages/c4/51/29046e48f693c54e5b7412216d447a1d8362c9653148d98c02cdf65fa733/certifi-2026.10.19-py3-none-any.whl", + "sha256": "42d35340cc5b9ba78e818ddbff0c5b1c2b779de448a340fd1b989f5fa8670e1b" + }, + { + "kind": "tool", + "name": "rpds-py", + "version": "2026.9.1", + "url": "https://files.pythonhosted.org/packages/42/ff/bf7d54f362748fd6a49277b9d6531c394074110fedf50ad791ec59133fbb/rpds_py-2026.9.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", + "sha256": "2693b2728bbcc48d09a981a356954b0c47c53ff25b545856f28a889ea619f69a" + }, + { + "kind": "tool", + "name": "rpds-py", + "version": "2026.9.1", + "url": "https://files.pythonhosted.org/packages/1d/6d/b26eb1e75395925b3a142ed351cbed2ec8212f5c9d937aee3df32c701baa/rpds_py-2026.9.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", + "sha256": "addeda51556dac7c1a2f14cda62db8b621cd12afba3091d03a96c72932387eab" + }, + { + "kind": "tool", + "name": "rpds-py", + "version": "2026.9.1", + "url": "https://files.pythonhosted.org/packages/72/e2/5873bc4643c250db9e05d48dc0c93763d4aa68bc3b81164cb1af3b45b284/rpds_py-2026.9.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", + "sha256": "07deecbfce94c78473018bc7d10b337cc651d12df87a1eb2cb3e4024bc9c33d0" + }, + { + "kind": "tool", + "name": "rpds-py", + "version": "2026.9.1", + "url": "https://files.pythonhosted.org/packages/22/9d/d08a1128ab199b2f0cf25bfeb0639bd05119fff4b7c47bec24ef9a8ec23f/rpds_py-2026.9.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", + "sha256": "eac2f5dbafd585dfe31f86a23ebf0d3ba480a9d49ebc87947267b5608d4ea0cd" + }, + { + "kind": "source", + "name": "pip-source", + "version": "26.2.2", + "url": "https://github.com/pypa/pip/archive/b3b696fe2122f2339d782517559bfade2cb6b879.tar.gz", + "sha256": "5202e6f34650ed74b8cfc74a4808af45a46ebd994b187e160a92d426e1bb3e0f" + }, + { + "kind": "tool", + "name": "pip", + "version": "26.2.2", + "url": "https://files.pythonhosted.org/packages/3f/06/3e4420302363fbb71be3c7f35ce042f54bfca330e3e66b3a2e3c4cca579f/pip-26.2.2-py3-none-any.whl", + "sha256": "fd7f4dfa8190e014013b9f08f3e973f4e4c26ffd179a204895533a7254813a70" + } + ] +} diff --git a/tools/pip-security-overlay/test-pip-overlay.py b/tools/pip-security-overlay/test-pip-overlay.py new file mode 100644 index 000000000..a2c626511 --- /dev/null +++ b/tools/pip-security-overlay/test-pip-overlay.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +"""Focused streaming regression, CLI and TLS controls for the installed wheel.""" +import argparse +import contextlib +import http.client +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer +import io +import json +from pathlib import Path +import ssl +import subprocess +import sys +import tempfile +import threading + +import pip +from pip._internal.network.utils import response_chunks +from pip._vendor import msgpack, requests, urllib3 +from pip._vendor.urllib3.exceptions import ProtocolError + + +class TrackedBody(io.BytesIO): + largest_readline = 0 + def readline(self, size=-1): + data = super().readline(size) + self.largest_readline = max(self.largest_readline, len(data)) + return data + + +class Socket: + def __init__(self, body): + self.body = body + def makefile(self, *_): + return self.body + + +def streamed(body): + wire = TrackedBody(b"HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n" + body) + origin = http.client.HTTPResponse(Socket(wire), method="GET") + origin.begin() + response = requests.Response() + response.status_code = 200 + response.raw = urllib3.response.HTTPResponse( + body=origin, original_response=origin, headers=dict(origin.headers.items()), + preload_content=False) + return response, wire + + +def boundary_tests(expect_fixed): + outcome = [] + for label, body in ( + ("chunk-size", b"f" * 131072), + ("chunk-trailer", b"3\r\nfoo\r\n0\r\n" + b"X" * 131072), + ): + response, wire = streamed(body) + error_description = "no exception" + try: + list(response_chunks(response)) + except Exception as error: + error_description = repr(error) + if expect_fixed: + assert isinstance(error, ProtocolError), repr(error) + assert "exceeded maximum allowed length" in str(error), str(error) + if expect_fixed: + assert error_description != "no exception", "malicious chunk line was accepted" + assert wire.largest_readline <= 65537, wire.largest_readline + else: + assert wire.largest_readline == 131072, (wire.largest_readline, error_description) + outcome.append({"path": label, "max_readline": wire.largest_readline}) + for body in (b"3\r\nfoo\r\n0\r\n\r\n", b"3;" + b"x" * 65532 + b"\r\nfoo\r\n0\r\n\r\n"): + response, _ = streamed(body) + assert b"".join(response_chunks(response)) == b"foo" + return outcome + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--expect-vulnerable", action="store_true") + args = parser.parse_args() + result = {"pip": pip.__version__, "urllib3": urllib3.__version__, + "streaming": boundary_tests(not args.expect_vulnerable)} + if args.expect_vulnerable: + print(json.dumps(result)); return + assert pip.__version__ == "26.2.2+pasturestack.1" + assert urllib3.__version__ == "2.8.0" + assert msgpack.Unpacker.__module__ == "pip._vendor.msgpack.fallback" + import importlib.util + assert importlib.util.find_spec("pip._vendor.msgpack._cmsgpack") is None + unpacker = msgpack.Unpacker() + unpacker.feed(b"\x83\x73\xc4\x00") + try: + unpacker.unpack() + except (ValueError, msgpack.OutOfData): + pass + try: + unpacker.skip() + except (ValueError, msgpack.OutOfData): + pass + with tempfile.TemporaryDirectory(prefix="pip-tls-") as name: + root = Path(name) + cert, key = root / "cert.pem", root / "key.pem" + subprocess.run(["openssl", "req", "-x509", "-newkey", "rsa:2048", "-nodes", + "-days", "1", "-subj", "/CN=localhost", "-addext", + "subjectAltName=DNS:localhost", "-keyout", str(key), "-out", str(cert)], + check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + class Handler(BaseHTTPRequestHandler): + def do_GET(self): + body = b"trusted fixture" + self.send_response(200); self.send_header("Content-Length", str(len(body))) + self.end_headers(); self.wfile.write(body) + def log_message(self, *_): + pass + server = ThreadingHTTPServer(("127.0.0.1", 0), Handler) + context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + context.minimum_version = ssl.TLSVersion.TLSv1_2 + context.load_cert_chain(cert, key) + server.socket = context.wrap_socket(server.socket, server_side=True) + thread = threading.Thread(target=server.serve_forever, daemon=True); thread.start() + try: + port = server.server_address[1] + session = requests.Session(); session.trust_env = False + assert session.get(f"https://localhost:{port}/", verify=str(cert), timeout=5).status_code == 200 + for url, verify in ((f"https://localhost:{port}/", True), + (f"https://127.0.0.1:{port}/", str(cert))): + try: + session.get(url, verify=verify, timeout=5) + except requests.exceptions.SSLError: + pass + else: + raise AssertionError("untrusted or wrong-host TLS was accepted") + finally: + server.shutdown(); server.server_close(); thread.join() + subprocess.run([sys.executable, "-m", "pip", "--version"], check=True) + subprocess.run([sys.executable, "-m", "pip", "check"], check=True) + result.update(tls_trusted="accepted", tls_untrusted="rejected", tls_wrong_host="rejected", + msgpack_implementation=msgpack.Unpacker.__module__, cli="passed") + print(json.dumps(result)) + + +if __name__ == "__main__": + if sys.flags.optimize: + raise RuntimeError("Security regression tests must not run with Python optimization") + main() From c65962f862cd094fd23fa859dc6efed2ed840d90 Mon Sep 17 00:00:00 2001 From: chen21019 <19357113+chen21019@users.noreply.github.com> Date: Fri, 23 Oct 2026 21:33:05 +0800 Subject: [PATCH 03/10] Add retained revisions for verified October runtime releases --- catalog-images.json | 269 +++++++++++++++++- infra-templates/healthcheck/2/README.md | 23 ++ infra-templates/healthcheck/2/README.zh-TW.md | 37 +++ .../healthcheck/2/docker-compose.yml | 19 ++ .../healthcheck/2/rancher-compose.yml | 18 ++ infra-templates/healthcheck/config.yml | 2 +- .../network-diagnostics/3/README.md | 47 +++ .../network-diagnostics/3/README.zh-TW.md | 42 +++ .../3/docker-compose.yml.tpl | 54 ++++ .../network-diagnostics/3/rancher-compose.yml | 92 ++++++ .../network-diagnostics/config.yml | 2 +- .../network-policy-manager/4/README.md | 48 ++++ .../network-policy-manager/4/README.zh-TW.md | 40 +++ .../4/docker-compose.yml | 35 +++ .../4/rancher-compose.yml | 9 + .../network-policy-manager/config.yml | 2 +- infra-templates/network-services/11/README.md | 58 ++++ .../network-services/11/README.zh-TW.md | 46 +++ .../11/docker-compose.yml.tpl | 95 +++++++ .../network-services/11/rancher-compose.yml | 77 +++++ infra-templates/network-services/config.yml | 2 +- .../secret-volume-driver/3/README.md | 58 ++++ .../secret-volume-driver/3/README.zh-TW.md | 44 +++ .../secret-volume-driver/3/docker-compose.yml | 34 +++ .../3/rancher-compose.yml | 27 ++ .../secret-volume-driver/config.yml | 2 +- .../system-image-preloader/3/README.md | 43 +++ .../system-image-preloader/3/README.zh-TW.md | 40 +++ .../3/docker-compose.yml.tpl | 34 +++ .../3/rancher-compose.yml | 116 ++++++++ .../system-image-preloader/config.yml | 2 +- .../vault-volume-driver/4/README.md | 77 +++++ .../vault-volume-driver/4/README.zh-TW.md | 70 +++++ .../vault-volume-driver/4/docker-compose.yml | 81 ++++++ .../vault-volume-driver/4/rancher-compose.yml | 69 +++++ .../vault-volume-driver/config.yml | 2 +- .../windows-container-networking/3/README.md | 31 ++ .../3/README.zh-TW.md | 16 ++ .../3/docker-compose.yml | 13 + .../3/rancher-compose.yml | 34 +++ .../windows-container-networking/config.yml | 2 +- integration/core/test_catalog.py | 182 ++++++++++-- scripts/audit_deployable_images.py | 13 +- 43 files changed, 1961 insertions(+), 46 deletions(-) create mode 100644 infra-templates/healthcheck/2/README.md create mode 100644 infra-templates/healthcheck/2/README.zh-TW.md create mode 100644 infra-templates/healthcheck/2/docker-compose.yml create mode 100644 infra-templates/healthcheck/2/rancher-compose.yml create mode 100644 infra-templates/network-diagnostics/3/README.md create mode 100644 infra-templates/network-diagnostics/3/README.zh-TW.md create mode 100644 infra-templates/network-diagnostics/3/docker-compose.yml.tpl create mode 100644 infra-templates/network-diagnostics/3/rancher-compose.yml create mode 100644 infra-templates/network-policy-manager/4/README.md create mode 100644 infra-templates/network-policy-manager/4/README.zh-TW.md create mode 100644 infra-templates/network-policy-manager/4/docker-compose.yml create mode 100644 infra-templates/network-policy-manager/4/rancher-compose.yml create mode 100644 infra-templates/network-services/11/README.md create mode 100644 infra-templates/network-services/11/README.zh-TW.md create mode 100644 infra-templates/network-services/11/docker-compose.yml.tpl create mode 100644 infra-templates/network-services/11/rancher-compose.yml create mode 100644 infra-templates/secret-volume-driver/3/README.md create mode 100644 infra-templates/secret-volume-driver/3/README.zh-TW.md create mode 100644 infra-templates/secret-volume-driver/3/docker-compose.yml create mode 100644 infra-templates/secret-volume-driver/3/rancher-compose.yml create mode 100644 infra-templates/system-image-preloader/3/README.md create mode 100644 infra-templates/system-image-preloader/3/README.zh-TW.md create mode 100644 infra-templates/system-image-preloader/3/docker-compose.yml.tpl create mode 100644 infra-templates/system-image-preloader/3/rancher-compose.yml create mode 100644 infra-templates/vault-volume-driver/4/README.md create mode 100644 infra-templates/vault-volume-driver/4/README.zh-TW.md create mode 100644 infra-templates/vault-volume-driver/4/docker-compose.yml create mode 100644 infra-templates/vault-volume-driver/4/rancher-compose.yml create mode 100644 infra-templates/windows-container-networking/3/README.md create mode 100644 infra-templates/windows-container-networking/3/README.zh-TW.md create mode 100644 infra-templates/windows-container-networking/3/docker-compose.yml create mode 100644 infra-templates/windows-container-networking/3/rancher-compose.yml diff --git a/catalog-images.json b/catalog-images.json index ae2761f0d..71dad76ff 100644 --- a/catalog-images.json +++ b/catalog-images.json @@ -232,7 +232,9 @@ "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"], + "platforms": [ + "linux/amd64" + ], "vulnerabilityScan": { "scanner": "Trivy 0.74.0", "reportCreatedAt": "2026-09-14", @@ -251,7 +253,9 @@ "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"], + "platforms": [ + "linux/amd64" + ], "vulnerabilityScan": { "scanner": "Trivy 0.74.0", "reportCreatedAt": "2026-09-14", @@ -270,7 +274,9 @@ "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"], + "platforms": [ + "linux/amd64" + ], "vulnerabilityScan": { "scanner": "Trivy 0.74.0", "reportCreatedAt": "2026-09-14", @@ -289,7 +295,9 @@ "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-10-05", - "platforms": ["linux/amd64"], + "platforms": [ + "linux/amd64" + ], "vulnerabilityScan": { "scanner": "Trivy 0.74.0", "reportCreatedAt": "2026-10-05T05:24:38.357634363Z", @@ -946,6 +954,259 @@ "critical": 0, "secrets": 0 } + }, + { + "sourceRepository": "https://github.com/PastureStack/network-diagnostics-agent", + "sourcePath": "Dockerfile", + "registryPage": "https://github.com/orgs/PastureStack/packages/container/package/network-diagnostics-agent", + "licenseBoundary": "Inherited Apache-2.0 source and image; Go toolchain material retains its upstream license and notice", + "platforms": [ + "linux/amd64" + ], + "reference": "ghcr.io/pasturestack/network-diagnostics-agent:v0.2.1", + "sourceCommit": "b837685df0c99b3e2ffe28ee927b82d5d7a5592d", + "manifestDigest": "sha256:974a045632eb3010eb315ada26aa820b59b5527bcd237487cf036702b66a01f1", + "reviewedAt": "2026-10-23", + "vulnerabilityScan": { + "scope": "published runtime image", + "high": 0, + "critical": 0, + "evidence": "https://github.com/PastureStack/network-diagnostics-agent/actions/runs/39958312029" + }, + "publicationVerification": { + "source": "component owner verified anonymous manifest/config readback", + "workflowRun": "https://github.com/PastureStack/network-diagnostics-agent/actions/runs/39958312029" + } + }, + { + "sourceRepository": "https://github.com/PastureStack/network-diagnostics-service", + "sourcePath": "Dockerfile", + "registryPage": "https://github.com/orgs/PastureStack/packages/container/package/network-diagnostics-service", + "licenseBoundary": "Apache-2.0 applies only to the new PastureStack root commit and image; historical unlicensed upstream source and history are excluded", + "platforms": [ + "linux/amd64" + ], + "reference": "ghcr.io/pasturestack/network-diagnostics-service:v0.2.1", + "sourceCommit": "166b95cd98bdf8a362221ce032c72d9159d02b36", + "manifestDigest": "sha256:7ba5dbb413aadfa289589f18bbfd11ac4ecad3e79bc04a14c86b2d32029b4b49", + "reviewedAt": "2026-10-23", + "vulnerabilityScan": { + "scope": "published runtime image", + "high": 0, + "critical": 0, + "evidence": "https://github.com/PastureStack/network-diagnostics-service/actions/runs/39958562655" + }, + "publicationVerification": { + "source": "component owner verified anonymous manifest/config readback", + "workflowRun": "https://github.com/PastureStack/network-diagnostics-service/actions/runs/39958562655" + } + }, + { + "sourceRepository": "https://github.com/PastureStack/metadata-healthcheck", + "sourcePath": "package/Dockerfile", + "registryPage": "https://github.com/orgs/PastureStack/packages/container/package/metadata-healthcheck", + "licenseBoundary": "Apache-2.0 source and image; bundled Ubuntu and HAProxy packages retain their upstream licenses", + "platforms": [ + "linux/amd64" + ], + "reference": "ghcr.io/pasturestack/metadata-healthcheck:v0.3.17", + "sourceCommit": "410993d3b3b2493bbd84a36f7d67cfefb8dd6705", + "manifestDigest": "sha256:1d7d7705f400c37d7087ba379657fe25f81019b97c3672e7633a36cfcc2725a1", + "reviewedAt": "2026-10-23", + "vulnerabilityScan": { + "scope": "published runtime image", + "high": 0, + "critical": 0, + "evidence": "https://github.com/PastureStack/metadata-healthcheck/actions/runs/39957352204" + }, + "publicationVerification": { + "source": "component owner verified anonymous manifest/config readback", + "workflowRun": "https://github.com/PastureStack/metadata-healthcheck/actions/runs/39957352204" + } + }, + { + "sourceRepository": "https://github.com/PastureStack/secrets-flexvolume-plugin", + "sourcePath": "package/Dockerfile", + "registryPage": "https://github.com/orgs/PastureStack/packages/container/package/secrets-flexvolume-plugin", + "licenseBoundary": "Apache-2.0 source and image; bundled Ubuntu, Go toolchain, and CA certificate packages retain their upstream licenses and notices", + "platforms": [ + "linux/amd64" + ], + "reference": "ghcr.io/pasturestack/secrets-flexvolume-plugin:v0.2.1", + "sourceCommit": "258a591302093503c33ec9bdaf26ad4e9ad17b5a", + "manifestDigest": "sha256:42c0102f96948882d4c62006ccbcf2e09ed8d5806f6b5356edd6d523e569a3de", + "reviewedAt": "2026-10-23", + "vulnerabilityScan": { + "scope": "published runtime image", + "high": 0, + "critical": 0, + "evidence": "https://github.com/PastureStack/secrets-flexvolume-plugin/actions/runs/39957288813" + }, + "publicationVerification": { + "source": "component owner verified anonymous manifest/config readback", + "workflowRun": "https://github.com/PastureStack/secrets-flexvolume-plugin/actions/runs/39957288813" + } + }, + { + "sourceRepository": "https://github.com/PastureStack/vault-secrets-bridge", + "sourcePath": "package/Dockerfile", + "registryPage": "https://github.com/orgs/PastureStack/packages/container/package/vault-secrets-bridge", + "licenseBoundary": "Apache-2.0 source and image; bundled Ubuntu, Go toolchain, and CA certificate packages retain their upstream licenses and notices", + "platforms": [ + "linux/amd64" + ], + "reference": "ghcr.io/pasturestack/vault-secrets-bridge:v0.1.2", + "sourceCommit": "dd5b0db64c87b0b20cdca7c6b93f4311b5e0aa56", + "manifestDigest": "sha256:73692de6f293923f86ba55211f3c90c00c177b25b2c6bc02c0068b2b0baabe40", + "reviewedAt": "2026-10-23", + "vulnerabilityScan": { + "scope": "published runtime image", + "high": 0, + "critical": 0, + "evidence": "https://github.com/PastureStack/vault-secrets-bridge/actions/runs/39956267852" + }, + "publicationVerification": { + "source": "component owner verified anonymous manifest/config readback", + "workflowRun": "https://github.com/PastureStack/vault-secrets-bridge/actions/runs/39956267852" + } + }, + { + "sourceRepository": "https://github.com/PastureStack/pod-pause-image", + "sourcePath": "Dockerfile", + "registryPage": "https://github.com/orgs/PastureStack/packages/container/package/pod-pause-image", + "licenseBoundary": "Apache-2.0 source and image; the pinned Ubuntu base and build packages retain their upstream licenses and notices", + "platforms": [ + "linux/amd64" + ], + "reference": "ghcr.io/pasturestack/pod-pause-image:v3.0.5", + "sourceCommit": "769c9aefdb45d50df9ac1aa48805a9d01b11c77f", + "manifestDigest": "sha256:edb454ffa5de459a01d33df386d423093d64e11dd28caeb4ab89fb2a5d1e454e", + "reviewedAt": "2026-10-23", + "vulnerabilityScan": { + "scope": "published runtime image", + "high": 0, + "critical": 0, + "evidence": "https://github.com/PastureStack/pod-pause-image/actions/runs/39958231883" + }, + "publicationVerification": { + "source": "component owner verified anonymous manifest/config readback", + "workflowRun": "https://github.com/PastureStack/pod-pause-image/actions/runs/39958231883" + } + }, + { + "sourceRepository": "https://github.com/PastureStack/network-plugin-manager", + "sourcePath": "package/Dockerfile", + "registryPage": "https://github.com/orgs/PastureStack/packages/container/package/network-plugin-manager", + "licenseBoundary": "Apache-2.0 source and image; bundled Alpine, Docker CLI, and other packages retain their upstream licenses and notices", + "platforms": [ + "linux/amd64" + ], + "reference": "ghcr.io/pasturestack/network-plugin-manager:v0.8.23", + "sourceCommit": "c7f6bf7f6ff76ca9730d918738f4eb20bc6659a6", + "manifestDigest": "sha256:09e2e1c13972f2859aa5e738558bee05a73a9280824375d7d3e966dc4b7133df", + "reviewedAt": "2026-10-23", + "vulnerabilityScan": { + "scope": "published runtime image", + "high": 0, + "critical": 0, + "evidence": "https://github.com/PastureStack/network-plugin-manager/actions/runs/39954592863" + }, + "publicationVerification": { + "source": "component owner verified anonymous manifest/config readback", + "workflowRun": "https://github.com/PastureStack/network-plugin-manager/actions/runs/39954592863" + } + }, + { + "sourceRepository": "https://github.com/PastureStack/metadata-service", + "sourcePath": "package/Dockerfile", + "registryPage": "https://github.com/orgs/PastureStack/packages/container/package/metadata-service", + "licenseBoundary": "Apache-2.0 source and image; bundled Ubuntu and other packages retain their upstream licenses and notices", + "platforms": [ + "linux/amd64" + ], + "reference": "ghcr.io/pasturestack/metadata-service:v0.10.5", + "sourceCommit": "9aa4b97c7907493f0c5a5ccf5ca2b708e7bce9f7", + "manifestDigest": "sha256:31f72a3c737a3b67bd1fb7d3c98d1ce728c84c52cad94f1884872f153efc4a01", + "reviewedAt": "2026-10-23", + "vulnerabilityScan": { + "scope": "published runtime image", + "high": 0, + "critical": 0, + "evidence": "https://github.com/PastureStack/metadata-service/actions/runs/39959381046" + }, + "publicationVerification": { + "source": "component owner verified anonymous manifest/config readback", + "workflowRun": "https://github.com/PastureStack/metadata-service/actions/runs/39959381046" + } + }, + { + "sourceRepository": "https://github.com/PastureStack/internal-dns", + "sourcePath": "package/linux/amd64/Dockerfile", + "registryPage": "https://github.com/orgs/PastureStack/packages/container/package/internal-dns", + "licenseBoundary": "Apache-2.0 source and image; bundled Ubuntu and other packages retain their upstream licenses and notices", + "platforms": [ + "linux/amd64" + ], + "reference": "ghcr.io/pasturestack/internal-dns:v0.17.13", + "sourceCommit": "8bd6b18c44957d08ee1570fe2391ed2299987ea7", + "manifestDigest": "sha256:ee75f485b1781378360e1baed6dca4e7de79c933ab80b27cc01c0ad723e093e5", + "reviewedAt": "2026-10-23", + "vulnerabilityScan": { + "scope": "published runtime image", + "high": 0, + "critical": 0, + "evidence": "https://github.com/PastureStack/internal-dns/actions/runs/39957348074" + }, + "publicationVerification": { + "source": "component owner verified anonymous manifest/config readback", + "workflowRun": "https://github.com/PastureStack/internal-dns/actions/runs/39957348074" + } + }, + { + "sourceRepository": "https://github.com/PastureStack/network-policy-manager", + "sourcePath": "package/Dockerfile", + "registryPage": "https://github.com/orgs/PastureStack/packages/container/package/network-policy-manager", + "licenseBoundary": "Apache-2.0 source and image; bundled Ubuntu, nftables, and other packages retain their upstream licenses and notices", + "platforms": [ + "linux/amd64" + ], + "reference": "ghcr.io/pasturestack/network-policy-manager:v0.3.2", + "sourceCommit": "44deaefcad4e2b806edbf0ec9f560ff57796cef2", + "manifestDigest": "sha256:6e4984bb831369a39f48ddc448ca9bb8b3d8c5ed1e5e0efe06261f59324d7b88", + "reviewedAt": "2026-10-23", + "vulnerabilityScan": { + "scope": "published runtime image", + "high": 0, + "critical": 0, + "evidence": "https://github.com/PastureStack/network-policy-manager/actions/runs/39958239844" + }, + "publicationVerification": { + "source": "component owner verified anonymous manifest/config readback", + "workflowRun": "https://github.com/PastureStack/network-policy-manager/actions/runs/39958239844" + } + }, + { + "sourceRepository": "https://github.com/PastureStack/system-image-preloader", + "sourcePath": "Dockerfile", + "registryPage": "https://github.com/orgs/PastureStack/packages/container/package/system-image-preloader", + "licenseBoundary": "Apache-2.0 source and image; bundled Ubuntu, Docker CLI, yq, gomplate, and other dependencies retain their upstream licenses and notices", + "platforms": [ + "linux/amd64" + ], + "reference": "ghcr.io/pasturestack/system-image-preloader:v0.3.1", + "sourceCommit": "24e175a679540a99ee93696338affeee7c2d332b", + "manifestDigest": "sha256:09e9ad1e70546aacb87ef843e39cd31aff9463ca04a0ada70654f153f07930b9", + "reviewedAt": "2026-10-23", + "vulnerabilityScan": { + "scope": "published runtime image", + "high": 0, + "critical": 0, + "evidence": "https://github.com/PastureStack/system-image-preloader/actions/runs/39958486019" + }, + "publicationVerification": { + "source": "component owner verified anonymous manifest/config readback", + "workflowRun": "https://github.com/PastureStack/system-image-preloader/actions/runs/39958486019" + } } ] } diff --git a/infra-templates/healthcheck/2/README.md b/infra-templates/healthcheck/2/README.md new file mode 100644 index 000000000..14a22e7d7 --- /dev/null +++ b/infra-templates/healthcheck/2/README.md @@ -0,0 +1,23 @@ + + +# Metadata Healthcheck v0.3.16 + +This infrastructure stack runs one healthcheck agent on every eligible host. The agent reads health declarations from the established link-local Metadata endpoint, manages its private HAProxy process, and reports stable state changes to the compatible control API. + +## Reviewed image + +- Image: `ghcr.io/pasturestack/metadata-healthcheck:v0.3.16` +- Source: [`PastureStack/metadata-healthcheck@df38ca1c4712ba4919c73fb329d87a1940b6970f`](https://github.com/PastureStack/metadata-healthcheck/tree/df38ca1c4712ba4919c73fb329d87a1940b6970f) +- Source license: Apache-2.0; bundled operating-system packages retain their upstream licenses +- Security gate: Trivy HIGH 0, CRITICAL 0, image secrets 0, and source secrets 0 +- Distribution gate: public GHCR and unauthenticated version-tag pull passed + +## Compatibility boundary + +The compatible control plane requires the literal `rancher-compose.yml` filename and the `io.rancher.*` labels in this template. They are protocol identifiers, not PastureStack branding. The `create_agent` flow supplies scoped per-instance credentials; the image translates those injected compatibility names to its public `PLATFORM_*` configuration only when explicit neutral values are absent. + +`PLATFORM_CA_ROOT` points to the established read-only agent certificate mount. TCP 42 is a container-network readiness endpoint and is not published on a host port. The template does not mount the Docker socket, request privileged mode, or add Linux capabilities. + +## Release boundary + +The image-level integration gate passed with the default link-local address, without a neutral Metadata DNS alias, and with routine lifecycle messages on standard output while actual failures remain on standard error. Earlier Catalog-created deployments verified credential injection, compatibility mapping, global scheduling, readiness, restart, two-daemon reporting, and removal. The stack remains a release candidate until v0.3.16 passes a fresh multi-host upgrade, rollback, and complete infrastructure-stack removal on isolated VM snapshots. Do not use this template to modify an existing production control plane. diff --git a/infra-templates/healthcheck/2/README.zh-TW.md b/infra-templates/healthcheck/2/README.zh-TW.md new file mode 100644 index 000000000..476627e0b --- /dev/null +++ b/infra-templates/healthcheck/2/README.zh-TW.md @@ -0,0 +1,37 @@ + + +# 中繼資料健康檢查 v0.3.16 + +此基礎架構堆疊會在每台符合條件的主機上執行一個健康檢查代理程式。 +代理程式從既有的連結本機中繼資料端點讀取健康狀態宣告、管理自己的 +HAProxy 處理程序,並把穩定的狀態變更回報給相容控制 API。 + +## 已審核映像 + +- 映像:`ghcr.io/pasturestack/metadata-healthcheck:v0.3.16` +- 原始碼: + [`PastureStack/metadata-healthcheck@df38ca1c4712ba4919c73fb329d87a1940b6970f`](https://github.com/PastureStack/metadata-healthcheck/tree/df38ca1c4712ba4919c73fb329d87a1940b6970f) +- 原始碼採 Apache-2.0 授權;作業系統套件保留各自的上游授權。 +- Trivy 結果為 HIGH 0、CRITICAL 0,映像及原始碼的機密資料掃描均為 0。 +- 公開 GHCR 與未登入拉取版本標籤的驗證已通過。 + +## 相容性界線 + +相容控制平面仍需要名為 `rancher-compose.yml` 的檔案及 +`io.rancher.*` 標籤。這些是協定識別名稱,不是目前的產品品牌。 +`create_agent` 流程會提供範圍受限的執行個體登入資訊;若未明確設定 +中性名稱,映像才會把相容名稱轉換成公開的 `PLATFORM_*` 設定。 + +`PLATFORM_CA_ROOT` 指向既有的唯讀代理程式憑證掛載。容器網路上的 +TCP 42 是就緒狀態端點,不會公開成主機連接埠。此範本不會掛載 Docker +Socket、不要求特權模式,也不新增 Linux Capability。 + +## 發布界線 + +映像層級的整合測試已使用預設連結本機位址通過,且不依賴中性的 +中繼資料 DNS 別名;一般生命週期訊息會寫入標準輸出,只有實際失敗 +才會寫入標準錯誤。較早的商店部署也驗證過登入資訊注入、相容名稱 +映射、全域排程、就緒狀態、重新啟動、雙常駐程式回報及移除流程。 +在 v0.3.16 於隔離 VM 快照完成新的多主機升級、回復及完整基礎架構 +堆疊移除測試前,此範本仍屬候選版本。請勿使用此範本直接變更既有的 +正式控制平面。 diff --git a/infra-templates/healthcheck/2/docker-compose.yml b/infra-templates/healthcheck/2/docker-compose.yml new file mode 100644 index 000000000..052785496 --- /dev/null +++ b/infra-templates/healthcheck/2/docker-compose.yml @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: MIT +version: '2' +services: + healthcheck: + image: ghcr.io/pasturestack/metadata-healthcheck:v0.3.17 + restart: always + command: + - --metadata-url + - http://169.254.169.250/2015-12-19 + environment: + PLATFORM_CA_ROOT: /var/lib/rancher/etc/ssl/ca.crt + labels: + io.rancher.container.create_agent: 'true' + io.rancher.scheduler.global: 'true' + logging: + driver: json-file + options: + max-size: 25m + max-file: '2' diff --git a/infra-templates/healthcheck/2/rancher-compose.yml b/infra-templates/healthcheck/2/rancher-compose.yml new file mode 100644 index 000000000..7820be5ab --- /dev/null +++ b/infra-templates/healthcheck/2/rancher-compose.yml @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: MIT +.catalog: + name: Metadata Healthcheck + version: v0.3.17 + description: Report metadata-defined workload health through the compatible control API. + minimum_rancher_version: v1.6.0 + +healthcheck: + scale: 1 + start_on_create: true + health_check: + port: 42 + interval: 2000 + response_timeout: 2000 + unhealthy_threshold: 3 + healthy_threshold: 2 + initializing_timeout: 60000 + reinitializing_timeout: 60000 diff --git a/infra-templates/healthcheck/config.yml b/infra-templates/healthcheck/config.yml index 21bebd7f5..7fb4706c6 100644 --- a/infra-templates/healthcheck/config.yml +++ b/infra-templates/healthcheck/config.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT name: Metadata Healthcheck description: Report metadata-defined workload health through the compatible control API. -version: v0.3.16 +version: v0.3.17 category: Infrastructure maintainer: PastureStack contributors license: MIT template; Apache-2.0 image and third-party package licenses apply diff --git a/infra-templates/network-diagnostics/3/README.md b/infra-templates/network-diagnostics/3/README.md new file mode 100644 index 000000000..35a38054c --- /dev/null +++ b/infra-templates/network-diagnostics/3/README.md @@ -0,0 +1,47 @@ + + +# PastureStack Network Diagnostics + +This infrastructure entry installs one authenticated aggregation service and +one non-root collector on every eligible managed host. The collectors send +only bounded aggregate counters and a pseudonymous host identifier. They do +not send interface names, IP or MAC addresses, routes, resolver values, host +names, container or process names, commands, environment variables, workload +content, files, credentials, or logs. + +## Installation + +Provide a random token containing 32 to 256 characters. The same token +authorizes collector uploads and operator API requests. It is masked by the +Catalog form, supplied only through container environment variables, and never +accepted as a command-line argument or written to application logs. + +The service publishes port `8091` by default so it does not conflict with the +control plane on port `8080`. After installation, open +`http://MANAGED_HOST:8091/` for the English operator page, or send +`Accept-Language: zh-TW` for Traditional Chinese. The health endpoint is +public; summary and bundle endpoints require +`Authorization: Bearer `. + +Snapshots are retained in the stack-owned `network-diagnostics-data` local +volume. Back up or migrate that volume before moving the service to another +host. Removing the stack may remove the volume depending on the control-plane +cleanup option selected by the operator. + +## Runtime boundary + +The agent is globally scheduled and reads only `/proc`, `/etc/resolv.conf`, +and `/etc/machine-id` through read-only mounts. The machine identifier is used +only as local input to an HMAC-SHA-256 pseudonym and is never transmitted. +Neither container requests privileged mode, host networking, host PID +visibility, Linux capabilities, a container-engine socket, or writable host +storage. The service runs as numeric user `65532` from a shell-free image. + +## License and provenance + +The template files are MIT-licensed PastureStack contributions. The agent +retains its inherited Apache License 2.0 and upstream history. The service is a +new Apache-2.0 PastureStack implementation whose historical upstream reference +has no repository-level license; historical source and history are excluded +from the current release. See each source repository and +`catalog-images.json` for the exact reviewed boundaries. diff --git a/infra-templates/network-diagnostics/3/README.zh-TW.md b/infra-templates/network-diagnostics/3/README.zh-TW.md new file mode 100644 index 000000000..7748baf63 --- /dev/null +++ b/infra-templates/network-diagnostics/3/README.zh-TW.md @@ -0,0 +1,42 @@ + + +# PastureStack 網路診斷 + +此基礎架構範本會安裝一個需要驗證的彙整服務,並在每台符合條件的 +受管主機上安裝一個非 root 蒐集器。蒐集器只會傳送有明確上限的彙整 +計數與去識別化主機代碼,不會傳送介面名稱、IP 或 MAC 位址、路由、 +DNS 解析設定、主機名稱、容器或處理程序名稱、命令、環境變數、工作 +負載內容、檔案、登入資訊或日誌。 + +## 安裝 + +請提供 32 到 256 個字元的隨機權杖。相同權杖用於授權蒐集器上傳及 +管理者 API 請求。商店表單會遮蔽此值;它只會透過容器環境變數提供, +不接受命令列參數,也不會寫入應用程式日誌。 + +服務預設公開 `8091` 連接埠,以免與使用 `8080` 的控制平面衝突。 +安裝後可開啟 `http://受管主機:8091/` 使用英文管理頁面,或送出 +`Accept-Language: zh-TW` 取得繁體中文。健康狀態端點可公開存取; +摘要與診斷封存端點則需提供 +`Authorization: Bearer `。 + +快照會保留在堆疊專用的 `network-diagnostics-data` 本機磁碟區。 +將服務移到其他主機前,請先備份或移轉該磁碟區。移除堆疊時是否刪除 +磁碟區,取決於管理者選擇的控制平面清理選項。 + +## 執行界線 + +代理程式採全域排程,只會透過唯讀掛載讀取 `/proc`、 +`/etc/resolv.conf` 與 `/etc/machine-id`。機器識別碼只作為本機 +HMAC-SHA-256 去識別化輸入,不會傳送出去。兩個容器均不要求特權 +模式、主機網路、主機 PID、Linux Capability、容器引擎 Socket 或 +可寫入的主機儲存空間。服務以數字使用者 `65532` 執行,映像不含 +Shell。 + +## 授權與出處 + +範本檔案是 PastureStack 依 MIT 授權提供的新貢獻。代理程式保留 +繼承的 Apache License 2.0 與上游歷史。服務是新的 Apache-2.0 +PastureStack 實作;由於歷史參考來源沒有儲存庫層級授權,該歷史 +原始碼與歷史紀錄不包含在目前版本中。精確的審核界線請參閱各原始碼 +儲存庫及 `catalog-images.json`。 diff --git a/infra-templates/network-diagnostics/3/docker-compose.yml.tpl b/infra-templates/network-diagnostics/3/docker-compose.yml.tpl new file mode 100644 index 000000000..e044301ea --- /dev/null +++ b/infra-templates/network-diagnostics/3/docker-compose.yml.tpl @@ -0,0 +1,54 @@ +# SPDX-License-Identifier: MIT +version: '2' + +services: + network-diagnostics-service: + image: ghcr.io/pasturestack/network-diagnostics-service:v0.2.1 + restart: always + environment: + PASTURESTACK_DIAGNOSTICS_TOKEN: '${COLLECTION_TOKEN}' + PASTURESTACK_DIAGNOSTICS_HISTORY_LENGTH: '${HISTORY_LENGTH}' + PASTURESTACK_DIAGNOSTICS_MAX_AGENTS: '${MAX_AGENTS}' + PASTURESTACK_DIAGNOSTICS_RETENTION_HOURS: '${RETENTION_HOURS}' + ports: + - '${PUBLISHED_PORT}:8080/tcp' + volumes: + - network-diagnostics-data:/var/lib/pasturestack-network-diagnostics + labels: + io.pasturestack.component: network-diagnostics-service + cpu_shares: 256 + mem_limit: 256m + logging: + driver: json-file + options: + max-size: 25m + max-file: '2' + + network-diagnostics-agent: + image: ghcr.io/pasturestack/network-diagnostics-agent:v0.2.1 + restart: always + environment: + PASTURESTACK_DIAGNOSTICS_TOKEN: '${COLLECTION_TOKEN}' + PASTURESTACK_DIAGNOSTICS_URL: 'http://network-diagnostics-service:8080' + PASTURESTACK_DIAGNOSTICS_INTERVAL_SECONDS: '${COLLECTION_INTERVAL_SECONDS}' + PASTURESTACK_DIAGNOSTICS_REQUEST_TIMEOUT_SECONDS: '${REQUEST_TIMEOUT_SECONDS}' + expose: + - '8090' + volumes: + - /proc:/host/proc:ro + - /etc/resolv.conf:/host/etc/resolv.conf:ro + - /etc/machine-id:/host/etc/machine-id:ro + labels: + io.pasturestack.component: network-diagnostics-agent + io.rancher.scheduler.global: 'true' + cpu_shares: 128 + mem_limit: 64m + logging: + driver: json-file + options: + max-size: 10m + max-file: '2' + +volumes: + network-diagnostics-data: + driver: local diff --git a/infra-templates/network-diagnostics/3/rancher-compose.yml b/infra-templates/network-diagnostics/3/rancher-compose.yml new file mode 100644 index 000000000..96e0433fb --- /dev/null +++ b/infra-templates/network-diagnostics/3/rancher-compose.yml @@ -0,0 +1,92 @@ +# SPDX-License-Identifier: MIT +version: '2' + +.catalog: + name: PastureStack Network Diagnostics + version: v0.2.2 + description: Collect bounded, pseudonymous host-network health summaries and retain operator-requested diagnostic bundles. + minimum_rancher_version: v1.6.13-rc1 + labels: + io.pasturestack.catalog.question.collection_token.label.zh-tw: '蒐集授權權杖' + io.pasturestack.catalog.question.collection_token.description.zh-tw: '32 到 256 個字元的隨機共用權杖,用於授權代理程式上傳與管理者 API 請求。' + io.pasturestack.catalog.question.published_port.label.zh-tw: '管理者連接埠' + io.pasturestack.catalog.question.published_port.description.zh-tw: '管理者連線到診斷服務的主機 TCP 連接埠;刻意避開控制平面通常使用的 8080。' + io.pasturestack.catalog.question.collection_interval_seconds.label.zh-tw: '蒐集間隔' + io.pasturestack.catalog.question.collection_interval_seconds.description.zh-tw: '兩次上傳有範圍限制的主機摘要之間的秒數。' + io.pasturestack.catalog.question.request_timeout_seconds.label.zh-tw: '請求逾時' + io.pasturestack.catalog.question.request_timeout_seconds.description.zh-tw: '單次上傳請求允許使用的秒數。' + io.pasturestack.catalog.question.history_length.label.zh-tw: '每台主機保留的快照數' + io.pasturestack.catalog.question.history_length.description.zh-tw: '每個去識別化主機可保留的快照上限。' + io.pasturestack.catalog.question.max_agents.label.zh-tw: '主機數上限' + io.pasturestack.catalog.question.max_agents.description.zh-tw: '服務可接受的不同去識別化主機數上限。' + io.pasturestack.catalog.question.retention_hours.label.zh-tw: '保留期限' + io.pasturestack.catalog.question.retention_hours.description.zh-tw: '快照與產生的診斷封存檔可保留的小時數。' + questions: + - variable: COLLECTION_TOKEN + label: Collection token + description: Random shared token containing 32 to 256 characters. It authorizes agent uploads and operator API requests. + type: password + required: true + - variable: PUBLISHED_PORT + label: Operator port + description: Host TCP port used to reach the diagnostics service. Port 8080 is intentionally avoided because it is normally used by the control plane. + type: int + default: 8091 + required: true + - variable: COLLECTION_INTERVAL_SECONDS + label: Collection interval + description: Seconds between bounded host summary uploads. + type: int + default: 600 + required: true + - variable: REQUEST_TIMEOUT_SECONDS + label: Request timeout + description: Seconds allowed for an individual upload request. + type: int + default: 15 + required: true + - variable: HISTORY_LENGTH + label: Snapshots per host + description: Maximum snapshots retained for each pseudonymous host. + type: int + default: 12 + required: true + - variable: MAX_AGENTS + label: Maximum hosts + description: Maximum distinct pseudonymous hosts accepted by the service. + type: int + default: 256 + required: true + - variable: RETENTION_HOURS + label: Retention period + description: Hours that snapshots and generated bundles remain available. + type: int + default: 24 + required: true + +network-diagnostics-service: + scale: 1 + start_on_create: true + health_check: + request_line: GET /healthz HTTP/1.0 + port: 8080 + interval: 10000 + initializing_timeout: 60000 + reinitializing_timeout: 60000 + response_timeout: 3000 + healthy_threshold: 2 + unhealthy_threshold: 3 + strategy: none + +network-diagnostics-agent: + start_on_create: true + health_check: + request_line: GET /healthz HTTP/1.0 + port: 8090 + interval: 10000 + initializing_timeout: 120000 + reinitializing_timeout: 120000 + response_timeout: 3000 + healthy_threshold: 2 + unhealthy_threshold: 3 + strategy: recreate diff --git a/infra-templates/network-diagnostics/config.yml b/infra-templates/network-diagnostics/config.yml index 4e4767aaa..6d83c7de7 100644 --- a/infra-templates/network-diagnostics/config.yml +++ b/infra-templates/network-diagnostics/config.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT name: Network Diagnostics description: Collect bounded, pseudonymous host-network health summaries and retain operator-requested diagnostic bundles. -version: v0.2.1 +version: v0.2.2 category: Monitoring maintainer: PastureStack contributors license: MIT template; image source and bundled dependency licenses apply diff --git a/infra-templates/network-policy-manager/4/README.md b/infra-templates/network-policy-manager/4/README.md new file mode 100644 index 000000000..f20653845 --- /dev/null +++ b/infra-templates/network-policy-manager/4/README.md @@ -0,0 +1,48 @@ + + +# PastureStack Network Policy Manager + +This infrastructure entry installs one policy agent on every eligible managed +host. Each agent reads the established link-local Metadata endpoint, compiles +the active network policy, and atomically replaces only +`table inet pasturestack_policy`. + +## Runtime behavior + +The agent checks Metadata every 20 seconds. Valid policy changes preserve +established and related connections, allow required system traffic, and apply +the configured default action to local application workloads. A transient +Metadata or policy error keeps the last-known-good table. If valid Metadata +remains unavailable for ten minutes, the agent enters a visible availability- +safe fail-open state and restores enforcement after reconciliation succeeds. + +The diagnostic readiness endpoint listens on host port `8092`. Rancher 1.6 +cannot address a health target for a host-network container without a container +IP, so this revision deliberately does not declare a Rancher health check that +would remain indefinitely in `initializing`. Operators can query `/readyz` +directly on each managed host; failures omit identifiers, addresses, labels, +selectors, and policy documents. + +## Security boundary + +The container uses host networking and only `NET_ADMIN`. It drops every other +capability, runs with a read-only root filesystem and +`no-new-privileges`, and does not use privileged mode, host PID, a +container-engine socket, host filesystem mounts, API credentials, or secret +input. + +Graceful stack removal stops reconciliation and deletes only the independently +owned nftables table. An unexpected container or host failure leaves the +last-known-good table in place. Review the source repository before changing +the polling, stale-data, or shutdown behavior. + +## License and provenance + +The template files and original icon are MIT-licensed PastureStack +contributions. The image source retains its Apache License 2.0, preserved +upstream history, authorship, and notices. Ubuntu, nftables, and bundled +dependencies retain their respective upstream licenses. + +PastureStack is an independent community effort to preserve, audit, and +modernize the Rancher 1.6 ecosystem. It is not affiliated with or endorsed by +Rancher Labs or SUSE. diff --git a/infra-templates/network-policy-manager/4/README.zh-TW.md b/infra-templates/network-policy-manager/4/README.zh-TW.md new file mode 100644 index 000000000..6676036f3 --- /dev/null +++ b/infra-templates/network-policy-manager/4/README.zh-TW.md @@ -0,0 +1,40 @@ + + +# PastureStack 網路政策管理器 + +此基礎架構範本會在每台符合條件的受管主機上安裝一個政策代理程式。 +每個代理程式都會讀取既有的連結本機中繼資料端點、編譯有效的網路 +政策,並以不可分割方式只替換 `table inet pasturestack_policy`。 + +## 執行方式 + +代理程式每 20 秒檢查一次中繼資料。有效政策變更會保留已建立及相關 +連線、允許必要系統流量,並把設定的預設動作套用到本機應用程式工作 +負載。暫時性中繼資料或政策錯誤會保留最後一份有效規則。若有效中繼 +資料持續無法使用十分鐘,代理程式會進入畫面可見、以維持可用性為主 +的開放狀態;協調成功後會自動恢復政策強制執行。 + +診斷用就緒狀態端點使用主機連接埠 `8092`。Rancher 1.6 無法為沒有 +容器 IP 的主機網路容器定位健康檢查目標,因此本版刻意不宣告會永遠 +停在「初始化中」的 Rancher 健康檢查。管理者可直接查詢每台受管主機 +的 `/readyz`;失敗回報不含識別碼、位址、標籤、選取條件或政策內容。 + +## 安全性界線 + +容器使用主機網路,且只保留 `NET_ADMIN`。其他 Capability 全部移除; +根檔案系統為唯讀並啟用 `no-new-privileges`。容器不使用特權模式、 +主機 PID、容器引擎 Socket、主機檔案掛載、API 登入資訊或機密資料 +輸入。 + +正常移除堆疊時會停止協調,並只刪除自己擁有的 nftables 表。非預期 +的容器或主機故障會保留最後一份有效規則。變更輪詢、過期資料或停止 +行為前,請先審查原始碼儲存庫。 + +## 授權與出處 + +範本檔案與原創圖示是 PastureStack 依 MIT 授權提供的新貢獻。映像 +原始碼保留 Apache License 2.0、上游歷史、作者與聲明。Ubuntu、 +nftables 及隨附相依套件保留各自的上游授權。 + +PastureStack 是獨立的社群計畫,目的在保存、稽核與現代化 Rancher +1.6 生態系;本計畫與 Rancher Labs 或 SUSE 無隸屬或背書關係。 diff --git a/infra-templates/network-policy-manager/4/docker-compose.yml b/infra-templates/network-policy-manager/4/docker-compose.yml new file mode 100644 index 000000000..de87b4f4d --- /dev/null +++ b/infra-templates/network-policy-manager/4/docker-compose.yml @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: MIT +version: '2' + +services: + network-policy-manager: + image: ghcr.io/pasturestack/network-policy-manager:v0.3.2 + command: + - serve + - --poll-interval + - 20s + - --fail-open-after + - 10m + - --health-listen + - 0.0.0.0:8092 + - --cleanup-on-exit + network_mode: host + cap_drop: + - ALL + cap_add: + - NET_ADMIN + read_only: true + tmpfs: + - /tmp:rw,noexec,nosuid,size=8m + security_opt: + - 'no-new-privileges:true' + labels: + io.pasturestack.component: network-policy-manager + io.rancher.scheduler.global: 'true' + cpu_shares: 128 + mem_limit: 64m + logging: + driver: json-file + options: + max-size: 10m + max-file: '2' diff --git a/infra-templates/network-policy-manager/4/rancher-compose.yml b/infra-templates/network-policy-manager/4/rancher-compose.yml new file mode 100644 index 000000000..34ce738bd --- /dev/null +++ b/infra-templates/network-policy-manager/4/rancher-compose.yml @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: MIT +.catalog: + name: PastureStack Network Policy Manager + version: v0.3.4 + description: Enforce metadata-defined network policy on every managed host with independently owned nftables rules. + minimum_rancher_version: v1.6.26-rc1 + +network-policy-manager: + start_on_create: true diff --git a/infra-templates/network-policy-manager/config.yml b/infra-templates/network-policy-manager/config.yml index a59ee9474..27a39d045 100644 --- a/infra-templates/network-policy-manager/config.yml +++ b/infra-templates/network-policy-manager/config.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT name: Network Policy Manager description: Enforce metadata-defined network policy on every managed host with independently owned nftables rules. -version: v0.3.3 +version: v0.3.4 category: Networking maintainer: PastureStack contributors license: MIT template; Apache-2.0 image and bundled dependency licenses apply diff --git a/infra-templates/network-services/11/README.md b/infra-templates/network-services/11/README.md new file mode 100644 index 000000000..b84eff7c1 --- /dev/null +++ b/infra-templates/network-services/11/README.md @@ -0,0 +1,58 @@ + + +# PastureStack Network Services + +Version 10 (visible version `v0.3.8`) uses the published Network Plugin Manager `v0.8.22` for CNI configuration convergence during an upgrade from the historical runtime. It retains single-backend selection, Metadata Service `v0.9.11`, Internal DNS `v0.17.11`, all Catalog questions, and version 9's forwarding and host-port contracts. Version 9 remains immutable. The image's official release provenance, manifest digest, and actual runtime scan evidence are recorded in `catalog-images.json`. + +## CNI configuration convergence + +The manager preflights all desired CNI configurations and writes each through an atomic replacement with mode `0600`. Only after every desired configuration has been written successfully may it retire an obsolete platform configuration. The historical `10-rancher.conf` must have the exact name/type/IPAM triplet `rancher-cni-network` / `rancher-bridge` / `rancher-cni-ipam`; the current `10-pasturestack.conf` must have `pasturestack-cni-network` / `pasture-bridge` / `metadata-cni-ipam`. The same ownership check applies when the selected provider requires the historical configuration again. + +Retirement renames the obsolete file with a `.pasturestack-retired` suffix, preserving its original bytes outside the CNI `.conf` / `.json` execution set. An existing retirement backup must be byte-identical; a conflicting backup causes an error. Unrelated administrator configurations are preserved. Malformed or partially matching platform configurations, symlinks, and unsafe metadata paths cause an explicit error. The manager never sweeps the configuration directory or removes CNI binary aliases as part of this migration. + +The official `v0.8.22` Release passed its all-severity runtime and secret gate with Trivy `0.74.0` after downloading the vulnerability database at `2026-10-07T02:47:02Z`. The published image and its SBOM both identify source commit `7b0920aa0c8f3b2c009c9c47c94c4d21b77c7077`. This revision still requires an exact-image managed upgrade check; component publication does not establish that an existing infrastructure stack has completed its upgrade. + +## Provider and lifecycle convergence + +The manager selects one eligible CNI provider per binary from the infrastructure-service metadata on the local host. The highest numeric OCI image version wins; an unversioned or nonnumeric development label cannot replace a numeric release, and ties use a deterministic immutable container-ID ordering. The generated wrapper stays bound to that exact provider and does not relist containers by service label at invocation time. It executes the provider's private `/opt/cni/bin` copy with a bounded compatibility fallback for older images. Wrapper replacement uses an exclusive temporary inode and atomic rename; content, file type, and mode drift are repaired without following a replacement symlink. + +When platform metadata temporarily reports a host-port container before its primary address, the manager may read the exact running container's network namespace. It accepts only one IPv4 address inside that network's configured managed subnet and revalidates the same Docker container PID after the namespace read. Missing, ambiguous, out-of-subnet, or lifecycle-raced results fail closed and retain the last known-good host-port rules until metadata and CNI converge. + +## Firewall backend + +`FIREWALL_BACKEND` defaults to `auto`. It reads Docker's actual firewall driver: Docker's native `nftables` driver uses native nft rules, while Docker's `iptables` driver selects the frontend that owns Docker's active NAT chain. That may be `iptables-nft` or `iptables-legacy` on **any supported host**, including Ubuntu 26.04 and later. The OS release, installed executable, or unloaded kernel module alone never selects a backend. To pin one path, choose: + +- `nftables`: Docker's native nftables firewall backend. This is **not** the same as the iptables-nft compatibility CLI. +- `iptables-nft`: xtables compatibility CLI backed by nf_tables, for Docker's iptables firewall driver. +- `iptables-legacy`: legacy xtables, only when the running Docker daemon actually owns the active rules through that frontend. + +The manager refuses a mismatched or ambiguous selection and does not fall back, switch Docker's backend, or load legacy modules. An Ubuntu 26.04+ host already using `iptables-legacy` or `iptables-nft` must keep its live Docker path; do not turn on native nftables merely because the OS is new. A deliberate migration requires a separate host change, rollback point, and network lifecycle test. + +This manager alone owns the host NAT and host-port `CATTLE_*` chains. Its +masquerade rules exclude destinations inside the managed overlay subnet in +all three backends; the IPsec host-XFRM router must not patch these chains. +For the per-host-subnet driver, the manager also excludes other active hosts' +validated subnets from masquerade and adds a bounded forwarding exception. +Inactive registrations are ignored; missing or overlapping labels on an active +host fail closed. This is a routed, unencrypted network; protect the host +transport separately. +Upgrade Network Services first and verify manager health on every host before +upgrading the matching IPsec Overlay version. + +Shared-subnet ingress is enabled only when CNI metadata explicitly sets +`allowSharedSubnetIngress: true`, or for the legacy fixed-subnet contract that +already declares both `bridgeSubnet` and `hostNat: true`. It is rejected for +host-label-based subnets, where only validated active peer ranges are trusted. + +For Docker's native nftables driver, configure Docker itself with `"firewall-backend": "nftables"` and `"bridge-accept-fwmark": "0x1068/0x1068"` before upgrading this stack. Persist `net.ipv4.ip_forward=1` on the host and verify it remains enabled after a reboot: Docker's native nftables backend does not enable IPv4 forwarding for you. The mark allows Docker's bridge forwarding rules to accept the manager's published-host-port traffic; the template cannot configure the host daemon or kernel settings. Check and explicitly migrate any stale `iptables-nft` `FORWARD DROP` policy or previous platform hooks before switching Docker. The manager refuses that mixed state rather than changing the host's global firewall policy. Docker's native nftables backend remains an experimental Docker feature; qualify it against the installed Docker release before production use. + +## Other configuration + +- `DOCKER_BRIDGE`: host bridge for managed workload traffic. +- `DNS_RECURSER_TIMEOUT`, `TTL`: upstream DNS timeout and service-discovery cache time. +- `CPU_PERIOD`, `CPU_QUOTA`: Metadata Service CPU scheduling limits. +- `RELOAD_INTERVAL_LIMIT`, `ARP_SYNC_INTERVAL`: metadata reload and host ARP reconciliation intervals. + +Network Plugin Manager still requires host networking, host PID visibility, the Docker socket, Docker state, kernel-module and runtime mounts, and the shared CNI volume. Metadata Service starts as root only to assign its link-local address, then drops to UID/GID 10001. Internal DNS shares its namespace. The `rancher-compose.yml` filename, `io.rancher.*` labels, `CATTLE_*` fallback variables, `/var/lib/rancher` CA path, and `rancher-cni-driver` volume are compatibility contracts, not a request to use legacy firewall rules. + +These template files are MIT-licensed. The manager, metadata service, and internal DNS retain their Apache-2.0 licenses and bundled dependency notices. Verify image source and the recorded manifest digest in `catalog-images.json` before deployment. diff --git a/infra-templates/network-services/11/README.zh-TW.md b/infra-templates/network-services/11/README.zh-TW.md new file mode 100644 index 000000000..cce067738 --- /dev/null +++ b/infra-templates/network-services/11/README.zh-TW.md @@ -0,0 +1,46 @@ + + +# PastureStack 網路服務 + +第 10 版(顯示版本 `v0.3.8`)使用已正式發布的網路外掛管理器 `v0.8.22`,修正從歷史執行環境升級時的 CNI 設定收斂。單一防火牆後端的選擇方式、中繼資料服務 `v0.9.11`、內部 DNS `v0.17.11`、所有 Catalog 問題,以及第 9 版的轉送與主機連接埠契約均維持原樣;第 9 版保留不可變的原始內容。官方映像來源、manifest digest 與實際執行環境掃描證據記錄於 `catalog-images.json`。 + +## CNI 設定收斂 + +管理器會先檢查所有預期 CNI 設定,再以原子置換逐檔寫入,權限為 `0600`。只有全部預期設定都寫入成功後,才可退役已不再使用的平台設定。歷史 `10-rancher.conf` 的 name/type/IPAM 必須完整符合 `rancher-cni-network` / `rancher-bridge` / `rancher-cni-ipam`;現行 `10-pasturestack.conf` 則必須完整符合 `pasturestack-cni-network` / `pasture-bridge` / `metadata-cni-ipam`。選定的 provider 再次需要歷史設定時,也會套用相同的身分判定。 + +退役時會將舊檔更名為加上 `.pasturestack-retired` 後綴的備份,保留原始位元組,並移出 CNI `.conf` / `.json` 執行集合。若備份已存在,其內容必須完全一致;內容衝突則明確報錯。管理者的其他設定會保留;格式損壞、只符合部分平台身分、符號連結及不安全的中繼資料路徑都會明確報錯。此次遷移不會掃除整個設定目錄,也不會移除 CNI 執行檔別名。 + +官方 `v0.8.22` Release 在 `2026-10-07T02:47:02Z` 下載弱點資料庫後,以 Trivy `0.74.0` 通過全嚴重程度的執行環境弱點與機密資料掃描。發布映像與 SBOM 均指向來源 commit `7b0920aa0c8f3b2c009c9c47c94c4d21b77c7077`。此版本仍須以正式映像完成受管升級驗收;元件發布並不代表既有基礎架構堆疊已完成升級。 + +## Provider 與生命週期收斂 + +管理器會依本機主機上的基礎架構服務中繼資料,為每個 CNI 執行檔選出唯一合格的 provider。數字型 OCI 映像版本以最高版為準;未標示版本或非數字的開發標籤不得取代正式數字版本,版本相同時再以不可變的容器 ID 做固定排序。產生的 wrapper 只綁定這個精確 provider,呼叫時不會再以服務標籤重新列舉容器。它優先執行 provider 私有的 `/opt/cni/bin` 程式,並只為舊映像保留有限的相容路徑。wrapper 以排他暫存 inode 與原子更名更新;內容、檔案型態或權限漂移時會安全修復,不會沿著遭置換的符號連結寫入。 + +若平台中繼資料暫時先出現主機連接埠容器、尚未填入主要位址,管理器可讀取該精確執行中容器的網路命名空間。只有該網路設定之受管子網路內恰好一個 IPv4 位址可被接受,讀取後還會再次確認同一 Docker 容器 PID。缺少、歧義、超出子網路或生命週期競態都會安全失敗,並保留上一份可用的主機連接埠規則,直到中繼資料與 CNI 完成收斂。 + +## 防火牆後端 + +`FIREWALL_BACKEND` 預設為 `auto`,依 Docker 實際防火牆驅動程式選擇單一路徑:Docker 原生 `nftables` 使用原生 nft 規則;Docker `iptables` 驅動程式則辨識哪一套前端擁有 Docker 現役 NAT 鏈。任何受支援主機(包括 Ubuntu 26.04 及更新版)都可能使用 `iptables-nft` 或 `iptables-legacy`;作業系統版本、執行檔存在或尚未載入的核心模組,均不足以決定後端。需要固定路徑時可選: + +- `nftables`:Docker 原生 nftables 防火牆後端,**不是** iptables-nft 相容命令。 +- `iptables-nft`:由 nf_tables 支援的 xtables 相容命令,搭配 Docker 的 iptables 防火牆驅動程式。 +- `iptables-legacy`:只在現役 Docker 確實透過這套前端持有規則時選用。 + +選擇與 Docker 實際後端不符或無法判定時,管理器會拒絕啟動,不會自動降級、切換 Docker 後端或載入 legacy 模組。Ubuntu 26.04 及更新版若已使用 `iptables-legacy` 或 `iptables-nft`,就應維持現役 Docker 路徑;不能只因系統較新便替它切成原生 nftables。刻意遷移須另外準備主機變更、回復點及網路生命週期驗收。 + +主機 NAT 與主機連接埠的 `CATTLE_*` 規則鏈只由此管理器維護;三種後端的來源位址轉換規則都排除受管 overlay 子網路內的目的位址。每主機子網路還會排除其他有效主機的已驗證子網路,並加入限定來源與目的子網路的轉送例外;非現役主機不列入,現役主機若缺少標籤或子網路重疊則安全地拒絕套用。此網路只提供路由、不加密,須另行保護主機間傳輸。IPsec 主機 XFRM 路由器不得再插入補丁規則。升級時應先升級網路服務,逐台確認管理器健康,再升級相符的 IPsec 加密網路版本。 + +只有 CNI 中繼資料明確設定 `allowSharedSubnetIngress: true` 時才啟用共用子網路輸入轉送;為維持既有固定子網路契約相容性,同時具有 `bridgeSubnet` 與 `hostNat: true` 的舊設定也會採用相同行為。使用主機標籤決定子網路時會拒絕此選項,只信任已驗證的現役對端範圍。 + +使用 Docker 原生 nftables 前,必須先在主機 Docker 設定加入 `"firewall-backend": "nftables"` 及 `"bridge-accept-fwmark": "0x1068/0x1068"`,再升級此堆疊。還須在主機持久設定 `net.ipv4.ip_forward=1`,並於重開機後確認仍啟用;Docker 原生 nftables 後端不會代為啟用 IPv4 轉送。此標記讓 Docker 網橋轉送規則接受管理器發布的主機連接埠流量;範本無法替主機設定 Docker daemon 或核心參數。切換前還須檢查並明確遷移殘留的 `iptables-nft FORWARD DROP` 全域政策與舊平台掛鉤。管理器遇到混用狀態會拒絕啟動,不會自行修改主機全域防火牆政策。Docker 原生 nftables 目前仍屬實驗性功能,正式環境使用前應針對安裝的 Docker 版本完成驗收。 + +## 其他設定 + +- `DOCKER_BRIDGE`:受管工作負載使用的主機網橋。 +- `DNS_RECURSER_TIMEOUT`、`TTL`:上游 DNS 逾時與服務探索快取時間。 +- `CPU_PERIOD`、`CPU_QUOTA`:中繼資料服務的 CPU 排程限制。 +- `RELOAD_INTERVAL_LIMIT`、`ARP_SYNC_INTERVAL`:中繼資料重新載入與主機 ARP 協調間隔。 + +網路外掛管理器仍需主機網路、主機 PID、Docker Socket、Docker 狀態、核心模組與執行環境掛載,以及共用 CNI 磁碟區。中繼資料服務僅在指派連結本機位址時以 root 啟動,之後切換為 UID/GID 10001;內部 DNS 與其共用網路命名空間。`rancher-compose.yml`、`io.rancher.*`、`CATTLE_*` 備援變數、`/var/lib/rancher` CA 路徑及 `rancher-cni-driver` 磁碟區是既有協定的相容契約,不代表必須使用 legacy 防火牆規則。 + +範本檔案採 MIT 授權;管理器、中繼資料服務與內部 DNS 保留 Apache-2.0 授權及隨附相依套件聲明。部署前應以 `catalog-images.json` 核對映像來源與記錄的 manifest digest。 diff --git a/infra-templates/network-services/11/docker-compose.yml.tpl b/infra-templates/network-services/11/docker-compose.yml.tpl new file mode 100644 index 000000000..bd42f19ad --- /dev/null +++ b/infra-templates/network-services/11/docker-compose.yml.tpl @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: MIT +version: '2' + +services: + network-plugin-manager: + image: ghcr.io/pasturestack/network-plugin-manager:v0.8.23 + privileged: true + network_mode: host + pid: host + command: + - network-plugin-manager + - --metadata-url + - http://169.254.169.250/2016-07-29 + - --arpsync-interval + - '${ARP_SYNC_INTERVAL}' + - --firewall-backend + - '${FIREWALL_BACKEND}' + environment: + DOCKER_BRIDGE: '${DOCKER_BRIDGE}' + METADATA_IP: 169.254.169.250 + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - /var/lib/docker:/var/lib/docker + - /lib/modules:/lib/modules:ro + - /run:/run + - /var/run:/var/run + - rancher-cni-driver:/etc/cni + - rancher-cni-driver:/opt/cni + labels: + io.pasturestack.component: network-plugin-manager + io.rancher.scheduler.global: 'true' + logging: + driver: json-file + options: + max-size: 25m + max-file: '2' + + metadata: + image: ghcr.io/pasturestack/metadata-service:v0.10.5 + user: root + cap_add: + - NET_ADMIN + network_mode: bridge + command: + - /bin/bash + - -ec + - | + export PLATFORM_URL="$${PLATFORM_URL:-$${CATTLE_URL:-}}" + export PLATFORM_ACCESS_KEY="$${PLATFORM_ACCESS_KEY:-$${CATTLE_ACCESS_KEY:-}}" + export PLATFORM_SECRET_KEY="$${PLATFORM_SECRET_KEY:-$${CATTLE_SECRET_KEY:-}}" + exec metadata-service --reload-interval-limit="${RELOAD_INTERVAL_LIMIT}" --subscribe + environment: + PLATFORM_CA_ROOT: /var/lib/rancher/etc/ssl/ca.crt + labels: + io.pasturestack.component: metadata-service + io.rancher.sidekicks: dns + io.rancher.container.create_agent: 'true' + io.rancher.scheduler.global: 'true' + io.rancher.container.agent_service.metadata: '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' + cpu_period: ${CPU_PERIOD} + cpu_quota: ${CPU_QUOTA} + + dns: + image: ghcr.io/pasturestack/internal-dns:v0.17.13 + network_mode: container:metadata + command: + - internal-dns + - --listen + - 169.254.169.250:53 + - --recurser-timeout + - '${DNS_RECURSER_TIMEOUT}' + - --ttl + - '${TTL}' + environment: + PLATFORM_METADATA_ENABLED: 'true' + PLATFORM_METADATA_URL: http://localhost/2016-07-29 + PLATFORM_METADATA_ANSWER: 169.254.169.250 + NEVER_RECURSE_TO: 169.254.169.250 + PLATFORM_DNS_ANSWERS_FILE: /etc/internal-dns/answers.json + labels: + io.pasturestack.component: internal-dns + io.rancher.scheduler.global: 'true' + logging: + driver: json-file + options: + max-size: 25m + max-file: '2' diff --git a/infra-templates/network-services/11/rancher-compose.yml b/infra-templates/network-services/11/rancher-compose.yml new file mode 100644 index 000000000..2b3a418f7 --- /dev/null +++ b/infra-templates/network-services/11/rancher-compose.yml @@ -0,0 +1,77 @@ +# SPDX-License-Identifier: MIT +.catalog: + name: PastureStack Network Services + version: v0.3.9 + description: Install host networking, metadata, and internal DNS services required by managed workloads. + minimum_rancher_version: v1.6.26-rc1 + labels: + io.pasturestack.catalog.question.docker_bridge.label.zh-tw: 'Docker 網橋' + io.pasturestack.catalog.question.docker_bridge.description.zh-tw: '受管工作負載流量使用的主機網橋。' + io.pasturestack.catalog.question.firewall_backend.label.zh-tw: '主機防火牆後端' + io.pasturestack.catalog.question.firewall_backend.description.zh-tw: '依 Docker 現役後端自動選擇;不論 Ubuntu 版本,原生 nftables、iptables-nft 與 iptables-legacy 互不混用。切換原生 nftables 前須先設定 Docker bridge-accept-fwmark。' + io.pasturestack.catalog.question.dns_recurser_timeout.label.zh-tw: 'DNS 遞迴查詢逾時' + io.pasturestack.catalog.question.dns_recurser_timeout.description.zh-tw: '等待上游 DNS 查詢回應的秒數。' + io.pasturestack.catalog.question.ttl.label.zh-tw: '服務探索 DNS 紀錄存留時間' + io.pasturestack.catalog.question.ttl.description.zh-tw: '內部服務探索 DNS 回應可保留的秒數。' + io.pasturestack.catalog.question.cpu_period.label.zh-tw: '中繼資料服務 CPU 週期' + io.pasturestack.catalog.question.cpu_period.description.zh-tw: '分配給每個中繼資料服務執行個體的 CPU 排程週期。' + io.pasturestack.catalog.question.cpu_quota.label.zh-tw: '中繼資料服務 CPU 配額' + io.pasturestack.catalog.question.cpu_quota.description.zh-tw: '分配給每個中繼資料服務執行個體的 CPU 配額。' + io.pasturestack.catalog.question.reload_interval_limit.label.zh-tw: '中繼資料重新載入間隔' + io.pasturestack.catalog.question.reload_interval_limit.description.zh-tw: '兩次中繼資料設定重新載入之間的最短毫秒數。' + io.pasturestack.catalog.question.arp_sync_interval.label.zh-tw: 'ARP 同步間隔' + io.pasturestack.catalog.question.arp_sync_interval.description.zh-tw: '兩次主機 ARP 協調作業之間的秒數。' + questions: + - variable: DOCKER_BRIDGE + label: Docker bridge + description: Host bridge used for managed workload traffic. + type: string + default: docker0 + required: true + - variable: FIREWALL_BACKEND + label: Host firewall backend + description: Follow Docker's active firewall backend on any supported Ubuntu version, or explicitly select native nftables, iptables-nft, or iptables-legacy. A mismatch fails safely; native nftables requires Docker bridge-accept-fwmark on the host. + type: enum + default: auto + required: true + options: + - auto + - nftables + - iptables-nft + - iptables-legacy + - variable: DNS_RECURSER_TIMEOUT + label: DNS recursion timeout + description: Seconds allowed for an upstream DNS query. + type: int + default: 2 + required: true + - variable: TTL + label: Service discovery TTL + description: Seconds that internal service-discovery answers remain valid. + type: int + default: 1 + required: true + - variable: CPU_PERIOD + label: Metadata CPU period + description: CPU scheduler period assigned to each metadata service instance. + type: int + default: 400000 + required: true + - variable: CPU_QUOTA + label: Metadata CPU quota + description: CPU quota assigned to each metadata service instance. + type: int + default: 200000 + required: true + - variable: RELOAD_INTERVAL_LIMIT + label: Metadata reload interval + description: Minimum milliseconds between metadata configuration reloads. + type: int + default: 1000 + required: true + - variable: ARP_SYNC_INTERVAL + label: ARP synchronization interval + description: Seconds between host ARP reconciliation passes. + type: int + default: 5 + required: true diff --git a/infra-templates/network-services/config.yml b/infra-templates/network-services/config.yml index 0330ebc5b..0f188f5a1 100644 --- a/infra-templates/network-services/config.yml +++ b/infra-templates/network-services/config.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT name: Network Services description: Install host networking, metadata, and internal DNS services required by managed workloads. -version: v0.3.8 +version: v0.3.9 category: Networking maintainer: PastureStack contributors license: MIT template; Apache-2.0 images and third-party package licenses apply diff --git a/infra-templates/secret-volume-driver/3/README.md b/infra-templates/secret-volume-driver/3/README.md new file mode 100644 index 000000000..0e48aa6ef --- /dev/null +++ b/infra-templates/secret-volume-driver/3/README.md @@ -0,0 +1,58 @@ +# PastureStack Secret Volume + +This infrastructure entry installs one host-local Docker volume driver on +every eligible managed host. The compatible control plane supplies an opaque +authorization token for each approved secret volume. The driver fetches only +the corresponding encrypted records, verifies their signatures, decrypts them +with the host identity key, and exposes read-only files to the target workload +through an isolated in-memory filesystem. + +## Security boundary + +The service uses +`ghcr.io/pasturestack/secrets-flexvolume-plugin:v0.1.1`. The Catalog and user +interface intentionally use the semantic version tag without a manifest +digest. + +The container: + +- drops all Linux capabilities before adding `SYS_ADMIN`, which is needed to + create and remove the isolated `tmpfs`, and `CHOWN`, which is needed to + apply the workload's requested numeric ownership to secret files, plus + `FOWNER`, which is needed to lock the final mode after that ownership + change; +- disables Docker's default AppArmor profile because that generic profile + blocks the required `tmpfs` mount syscall; the container remains + non-privileged, drops every capability except `SYS_ADMIN`, `CHOWN`, and + `FOWNER`, uses `no-new-privileges`, and is constrained by the remaining + controls below; +- uses a read-only root filesystem and a bounded, non-executable temporary + directory; +- does not use privileged mode, host networking, the host PID namespace, or a + container-engine socket; +- reads the host identity key through one read-only bind mount; and +- writes only its Docker plugin socket and the dedicated shared volume root. + +Secret files accept only safe relative paths, bounded UID and GID values, and +read-only modes. Values, tokens, credentials, identity keys, file names, and +encrypted envelopes are excluded from health responses and logs. A volume is +unmounted and erased after its final workload consumer releases it. + +## Workload use + +Create a secret through the compatible control plane, then select it from a +workload's **Secrets** section. The control plane creates the required volume +and supplies the authorization token; operators do not place secret material +in Compose, Catalog answers, or command-line arguments. + +The driver registers as `pasturestack-secret-volume`. Health faults are +reported without automatically recreating the driver container so that active +mounts are not disturbed by a restart loop. + +Source, operating instructions, security details, licensing, and release +evidence are available from the +[PastureStack Secret Volume Driver repository](https://github.com/PastureStack/secrets-flexvolume-plugin). + +PastureStack is an independent community effort to preserve, audit, and +modernize the Rancher 1.6 ecosystem. It is not affiliated with or endorsed by +Rancher Labs or SUSE. diff --git a/infra-templates/secret-volume-driver/3/README.zh-TW.md b/infra-templates/secret-volume-driver/3/README.zh-TW.md new file mode 100644 index 000000000..2a15224e8 --- /dev/null +++ b/infra-templates/secret-volume-driver/3/README.zh-TW.md @@ -0,0 +1,44 @@ +# PastureStack 機密資料磁碟區 + +此基礎架構範本會在每台符合條件的受管主機上安裝一個主機本機 Docker +磁碟區驅動程式。相容控制平面會為每個已核准的機密資料磁碟區提供不透明 +授權權杖。驅動程式只會取得對應的加密紀錄、驗證簽章、使用主機身分 +金鑰解密,再透過隔離的記憶體檔案系統向目標工作負載提供唯讀檔案。 + +## 安全性界線 + +服務使用 `ghcr.io/pasturestack/secrets-flexvolume-plugin:v0.1.1`。 +商店與使用者介面只顯示語意化版本標籤,不顯示映像摘要。 + +容器: + +- 先移除所有 Linux Capability,再加入建立及移除隔離 `tmpfs` 所需 + 的 `SYS_ADMIN`、套用工作負載要求數字擁有者所需的 `CHOWN`,以及 + 變更擁有者後鎖定最終模式所需的 `FOWNER`; +- 停用 Docker 預設 AppArmor 設定檔,因為該通用設定會阻擋必要的 + `tmpfs` 掛載系統呼叫;容器仍不是特權容器、只保留上述三個 + Capability、啟用 `no-new-privileges`,並受下列其他控制限制; +- 使用唯讀根檔案系統與有容量上限、不可執行的暫存目錄; +- 不使用特權模式、主機網路、主機 PID 或容器引擎 Socket; +- 只透過一個唯讀綁定掛載讀取主機身分金鑰;以及 +- 只寫入 Docker 外掛 Socket 與專用共用磁碟區根目錄。 + +機密資料檔案只接受安全的相對路徑、有範圍限制的 UID/GID,以及唯讀 +模式。健康狀態回應與日誌均排除資料值、權杖、登入資訊、身分金鑰、 +檔名及加密封裝。最後一個工作負載使用者釋放磁碟區後,磁碟區會卸載 +並清除。 + +## 工作負載使用方式 + +請先透過相容控制平面建立機密資料,再從工作負載的「機密資料」區段 +選取。控制平面會建立必要磁碟區並提供授權權杖;管理者不需把機密資料 +放入 Compose、商店答案或命令列參數。 + +驅動程式註冊名稱為 `pasturestack-secret-volume`。健康狀態故障不會 +自動重建驅動程式容器,以免重新啟動循環干擾正在使用的掛載。 + +原始碼、操作方式、安全性、授權及發布證據請參閱 +[PastureStack 機密資料磁碟區驅動程式儲存庫](https://github.com/PastureStack/secrets-flexvolume-plugin)。 + +PastureStack 是獨立的社群計畫,目的在保存、稽核與現代化 Rancher +1.6 生態系;本計畫與 Rancher Labs 或 SUSE 無隸屬或背書關係。 diff --git a/infra-templates/secret-volume-driver/3/docker-compose.yml b/infra-templates/secret-volume-driver/3/docker-compose.yml new file mode 100644 index 000000000..42ddaafbb --- /dev/null +++ b/infra-templates/secret-volume-driver/3/docker-compose.yml @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: MIT +version: '2' + +services: + secret-volume-driver: + image: ghcr.io/pasturestack/secrets-flexvolume-plugin:v0.2.1 + cap_drop: + - ALL + cap_add: + - SYS_ADMIN + - CHOWN + - FOWNER + read_only: true + tmpfs: + - /tmp:rw,noexec,nosuid,nodev,size=16m + security_opt: + - 'apparmor:unconfined' + - 'no-new-privileges:true' + labels: + io.pasturestack.component: secret-volume-driver + io.rancher.container.agent.role: environment,agent + io.rancher.container.create_agent: 'true' + io.rancher.scheduler.global: 'true' + volumes: + - /run/docker/plugins:/run/docker/plugins + - /var/lib/pasturestack/volumes:/var/lib/pasturestack/volumes:shared + - /var/lib/rancher/etc/ssl/host.key:/var/lib/pasturestack/etc/ssl/host.key:ro + cpu_shares: 128 + mem_limit: 96m + logging: + driver: json-file + options: + max-size: 10m + max-file: '2' diff --git a/infra-templates/secret-volume-driver/3/rancher-compose.yml b/infra-templates/secret-volume-driver/3/rancher-compose.yml new file mode 100644 index 000000000..dea4ea5aa --- /dev/null +++ b/infra-templates/secret-volume-driver/3/rancher-compose.yml @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: MIT +.catalog: + name: PastureStack Secret Volume + version: v0.1.3 + description: Deliver approved encrypted secrets to workloads through isolated in-memory volumes. + minimum_rancher_version: v1.6.15-rc1 + +secret-volume-driver: + storage_driver: + name: pasturestack-secret-volume + description: Secure in-memory secret volume driver + scope: local + create_supported: false + volume_access_mode: singleHostRW + volume_capabilities: + - secrets + start_on_create: true + health_check: + request_line: GET /readyz HTTP/1.0 + port: 8093 + interval: 10000 + initializing_timeout: 120000 + reinitializing_timeout: 120000 + response_timeout: 3000 + healthy_threshold: 2 + unhealthy_threshold: 3 + strategy: none diff --git a/infra-templates/secret-volume-driver/config.yml b/infra-templates/secret-volume-driver/config.yml index ddfe31595..c29a96f32 100644 --- a/infra-templates/secret-volume-driver/config.yml +++ b/infra-templates/secret-volume-driver/config.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT name: Secret Volume description: Deliver approved encrypted secrets to workloads through isolated in-memory volumes. -version: v0.1.2 +version: v0.1.3 category: Storage maintainer: PastureStack contributors license: MIT template; Apache-2.0 image and bundled dependency licenses apply diff --git a/infra-templates/system-image-preloader/3/README.md b/infra-templates/system-image-preloader/3/README.md new file mode 100644 index 000000000..1f4764efa --- /dev/null +++ b/infra-templates/system-image-preloader/3/README.md @@ -0,0 +1,43 @@ + + +# PastureStack System Image Preloader v0.3.0 + +This global, start-once infrastructure service discovers the images used by +compatible system stacks and asks each host Docker daemon to cache images that +are not already present. + +## Reviewed image + +- Image: `ghcr.io/pasturestack/system-image-preloader:v0.3.0` +- Source: [`PastureStack/system-image-preloader@150c78dbdb3f487a7003c83339cca5b76dde97f4`](https://github.com/PastureStack/system-image-preloader/tree/150c78dbdb3f487a7003c83339cca5b76dde97f4) +- Source license: Apache-2.0; Ubuntu, Docker CLI, `yq`, `gomplate`, and their + dependencies retain their upstream licenses and notices +- Security gate: Trivy HIGH 0 and CRITICAL 0 +- Distribution gate: public GHCR and anonymous version-tag manifest access + passed + +## Security boundary + +The service mounts `/var/run/docker.sock` read-write. Docker socket access is +equivalent to host administrator access, so deploy only the reviewed image and +restrict who can edit this stack. The service receives scoped compatibility API +credentials automatically and never enables credential-bearing shell tracing. + +Private-registry credentials are optional. When enabled, the selected host +Docker `config.json` is mounted read-only. Privileged mode remains off by +default and should be enabled only when required by the host security policy. +Image-pull retries and CPU-pressure waits are bounded. + +The compatible control plane requires the literal `rancher-compose.yml` +filename and `io.rancher.*` agent and scheduling labels in this template. They +are protocol identifiers, not PastureStack branding. + +## Validation + +The release passed offline retry and URL-contract tests, container help and +version smoke tests, OCI metadata and license checks, a current HIGH/CRITICAL +vulnerability scan, and an isolated end-to-end lifecycle test. The lifecycle +test used mock metadata, environment, and Catalog APIs and verified that the +runtime discovered a Compose image and cached its semantic tag through a real +Docker socket. It removed only its exact test resources and performed no broad +prune. diff --git a/infra-templates/system-image-preloader/3/README.zh-TW.md b/infra-templates/system-image-preloader/3/README.zh-TW.md new file mode 100644 index 000000000..7dcd5a591 --- /dev/null +++ b/infra-templates/system-image-preloader/3/README.zh-TW.md @@ -0,0 +1,40 @@ + + +# PastureStack 系統映像預先下載 v0.3.0 + +此全域、只執行一次的基礎架構服務會找出相容系統堆疊使用的映像,並 +要求每台主機的 Docker 常駐程式預先快取尚未存在的映像。 + +## 已審核映像 + +- 映像:`ghcr.io/pasturestack/system-image-preloader:v0.3.0` +- 原始碼: + [`PastureStack/system-image-preloader@150c78dbdb3f487a7003c83339cca5b76dde97f4`](https://github.com/PastureStack/system-image-preloader/tree/150c78dbdb3f487a7003c83339cca5b76dde97f4) +- 原始碼採 Apache-2.0 授權;Ubuntu、Docker CLI、`yq`、`gomplate` + 及相依套件保留各自的上游授權及聲明。 +- Trivy 掃描結果為 HIGH 0、CRITICAL 0。 +- 公開 GHCR 與未登入存取版本標籤的驗證已通過。 + +## 安全性界線 + +此服務需要以讀寫方式掛載 `/var/run/docker.sock`。Docker Socket +權限等同主機管理者權限,因此只能部署經審核的映像,並限制可編輯此 +堆疊的使用者。服務會自動取得範圍受限的相容 API 登入資訊,且不會 +啟用可能顯示登入資訊的 Shell 追蹤。 + +私有登錄登入資訊為選用功能。啟用後,選取的主機 Docker +`config.json` 會以唯讀方式掛載。特權模式預設關閉,只能在主機 +安全性政策確實要求時啟用。映像拉取重試與 CPU 使用量等待都有明確 +上限。 + +相容控制平面仍需要名為 `rancher-compose.yml` 的檔案及 +`io.rancher.*` 代理程式與排程標籤。這些是協定識別名稱,不是目前 +的產品品牌。 + +## 驗證 + +此版本已通過離線重試與 URL 契約測試、容器說明及版本煙霧測試、 +OCI 中繼資料與授權檢查、弱點掃描,以及隔離環境端對端生命週期測試。 +生命週期測試使用模擬中繼資料、環境及商店 API,並透過真正的 Docker +Socket 驗證執行環境能找出 Compose 映像及快取其語意化版本標籤。 +測試只移除精確建立的資源,沒有執行大範圍清理。 diff --git a/infra-templates/system-image-preloader/3/docker-compose.yml.tpl b/infra-templates/system-image-preloader/3/docker-compose.yml.tpl new file mode 100644 index 000000000..7bcfa1f3a --- /dev/null +++ b/infra-templates/system-image-preloader/3/docker-compose.yml.tpl @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: MIT +version: '2' +services: + system-image-preloader: + image: ghcr.io/pasturestack/system-image-preloader:v0.3.1 + {{ if eq .Values.PRIVILEGED "true"}} + privileged: true + {{ end}} + environment: + CHECK_CPU_USAGE: '${CHECK_CPU_USAGE}' + CPU_USAGE_MAX: '${CPU_USAGE_MAX}' + CPU_USAGE_SLEEP: '${CPU_USAGE_SLEEP}' + CPU_WAIT_MAX_ATTEMPTS: '${CPU_WAIT_MAX_ATTEMPTS}' + IMAGE_PULL_MAX_ATTEMPTS: '${IMAGE_PULL_MAX_ATTEMPTS}' + IMAGE_PULL_RETRY_DELAY_SECONDS: '${IMAGE_PULL_RETRY_DELAY_SECONDS}' + PLATFORM_AGENT_IMAGE: '${PLATFORM_AGENT_IMAGE}' + PLATFORM_TLS_VERIFY: '${PLATFORM_TLS_VERIFY}' + PLATFORM_VERSION: '${PLATFORM_VERSION}' + RANDOM_SLEEP: '${RANDOM_SLEEP}' + volumes: + - /var/run/docker.sock:/var/run/docker.sock + {{ if eq .Values.MOUNT_DOCKER_CONFIG "true"}} + - ${DOCKER_CONFIG_LOCATION}:/root/.docker/config.json:ro + {{ end}} + labels: + io.rancher.container.agent.role: environment + io.rancher.container.start_once: 'true' + io.rancher.container.create_agent: 'true' + io.rancher.scheduler.global: 'true' + logging: + driver: json-file + options: + max-size: 25m + max-file: '2' diff --git a/infra-templates/system-image-preloader/3/rancher-compose.yml b/infra-templates/system-image-preloader/3/rancher-compose.yml new file mode 100644 index 000000000..9fa58a199 --- /dev/null +++ b/infra-templates/system-image-preloader/3/rancher-compose.yml @@ -0,0 +1,116 @@ +# SPDX-License-Identifier: MIT +version: '2' +.catalog: + name: PastureStack System Image Preloader + version: v0.3.1 + description: Preload the container images required by compatible infrastructure stacks. + minimum_rancher_version: v1.6.15-rc1 + labels: + io.pasturestack.catalog.question.check_cpu_usage.label.zh-tw: '拉取前檢查 CPU 使用率' + io.pasturestack.catalog.question.check_cpu_usage.description.zh-tw: '主機 CPU 使用率高於設定上限時暫停等待。' + io.pasturestack.catalog.question.cpu_usage_max.label.zh-tw: 'CPU 使用率上限' + io.pasturestack.catalog.question.cpu_usage_max.description.zh-tw: '開始拉取映像前可接受的最高主機 CPU 使用率百分比。' + io.pasturestack.catalog.question.cpu_usage_sleep.label.zh-tw: 'CPU 檢查重試間隔' + io.pasturestack.catalog.question.cpu_usage_sleep.description.zh-tw: '兩次 CPU 使用率檢查之間等待的秒數。' + io.pasturestack.catalog.question.cpu_wait_max_attempts.label.zh-tw: 'CPU 檢查次數上限' + io.pasturestack.catalog.question.cpu_wait_max_attempts.description.zh-tw: '達到此檢查次數仍無法拉取時,以錯誤結束。' + io.pasturestack.catalog.question.image_pull_max_attempts.label.zh-tw: '映像拉取次數上限' + io.pasturestack.catalog.question.image_pull_max_attempts.description.zh-tw: '每個映像拉取失敗達到此次數時,以錯誤結束。' + io.pasturestack.catalog.question.image_pull_retry_delay_seconds.label.zh-tw: '映像拉取重試間隔' + io.pasturestack.catalog.question.image_pull_retry_delay_seconds.description.zh-tw: '映像拉取失敗後等待的秒數。' + io.pasturestack.catalog.question.mount_docker_config.label.zh-tw: '掛載 Docker 用戶端設定' + io.pasturestack.catalog.question.mount_docker_config.description.zh-tw: '從選取的主機檔案讀取私有登錄登入資訊。' + io.pasturestack.catalog.question.docker_config_location.label.zh-tw: 'Docker 用戶端設定路徑' + io.pasturestack.catalog.question.docker_config_location.description.zh-tw: 'Docker 用戶端 config.json 檔案的主機絕對路徑。' + io.pasturestack.catalog.question.privileged.label.zh-tw: '以特權模式執行' + io.pasturestack.catalog.question.privileged.description.zh-tw: '只有主機安全性政策確實要求時才能啟用。' + io.pasturestack.catalog.question.random_sleep.label.zh-tw: '分散各主機的映像拉取時間' + io.pasturestack.catalog.question.random_sleep.description.zh-tw: '依中繼資料為各主機加入不同的隨機延遲。' + io.pasturestack.catalog.question.platform_agent_image.label.zh-tw: '其他代理程式映像' + io.pasturestack.catalog.question.platform_agent_image.description.zh-tw: '基礎架構映像完成後要額外預先下載的選用語意化映像標籤。' + io.pasturestack.catalog.question.platform_version.label.zh-tw: '相容平台版本' + io.pasturestack.catalog.question.platform_version.description.zh-tw: '選取相容商店範本修訂版時使用的平台版本。' + io.pasturestack.catalog.question.platform_tls_verify.label.zh-tw: '驗證平台 TLS 憑證' + io.pasturestack.catalog.question.platform_tls_verify.description.zh-tw: '要求相容 API 使用受信任的 TLS 憑證。' + questions: + - variable: CHECK_CPU_USAGE + label: Check CPU usage before pulling + description: Wait while host CPU usage is above the configured limit. + type: boolean + default: true + required: true + - variable: CPU_USAGE_MAX + label: Maximum CPU usage + description: Highest host CPU usage percentage accepted before a pull. + type: int + default: 75 + required: true + - variable: CPU_USAGE_SLEEP + label: CPU retry delay + description: Seconds to wait between CPU usage checks. + type: int + default: 30 + required: true + - variable: CPU_WAIT_MAX_ATTEMPTS + label: Maximum CPU checks + description: Stop with an error after this many CPU usage checks. + type: int + default: 60 + required: true + - variable: IMAGE_PULL_MAX_ATTEMPTS + label: Maximum image pull attempts + description: Stop with an error after this many failed pulls per image. + type: int + default: 5 + required: true + - variable: IMAGE_PULL_RETRY_DELAY_SECONDS + label: Image pull retry delay + description: Seconds to wait after a failed image pull. + type: int + default: 10 + required: true + - variable: MOUNT_DOCKER_CONFIG + label: Mount a Docker client configuration + description: Read private-registry credentials from the selected host file. + type: boolean + default: false + required: true + - variable: DOCKER_CONFIG_LOCATION + label: Docker client configuration path + description: Absolute host path of the Docker client config.json file. + type: string + default: /root/.docker/config.json + required: true + - variable: PRIVILEGED + label: Run in privileged mode + description: Enable only when the host security policy requires it. + type: boolean + default: false + required: true + - variable: RANDOM_SLEEP + label: Stagger image pulls between hosts + description: Add a metadata-derived random delay between image pulls. + type: boolean + default: false + required: true + - variable: PLATFORM_AGENT_IMAGE + label: Additional agent image + description: Optional semantic image tag to preload after infrastructure images. + type: string + default: '' + required: false + - variable: PLATFORM_VERSION + label: Compatible platform version + description: Version used when selecting compatible Catalog template revisions. + type: string + default: v1.6.282 + required: true + - variable: PLATFORM_TLS_VERIFY + label: Verify platform TLS certificates + description: Require a trusted certificate for compatibility API requests. + type: boolean + default: false + required: true + +system-image-preloader: + start_on_create: true diff --git a/infra-templates/system-image-preloader/config.yml b/infra-templates/system-image-preloader/config.yml index 9aef6c46b..cdbe17177 100644 --- a/infra-templates/system-image-preloader/config.yml +++ b/infra-templates/system-image-preloader/config.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT name: System Image Preloader description: Preload the container images required by compatible infrastructure stacks. -version: v0.3.0 +version: v0.3.1 category: System maintainer: PastureStack contributors license: MIT template; Apache-2.0 image and bundled dependency licenses apply diff --git a/infra-templates/vault-volume-driver/4/README.md b/infra-templates/vault-volume-driver/4/README.md new file mode 100644 index 000000000..65dca5be3 --- /dev/null +++ b/infra-templates/vault-volume-driver/4/README.md @@ -0,0 +1,77 @@ +# PastureStack Vault Volume + +This infrastructure entry installs one unprivileged environment bridge and one +host-local Docker volume driver on every eligible managed host. A workload +requests an allowed policy set; the driver signs the request with the host +identity key, and the bridge verifies the active host before asking Vault for a +short-lived, response-wrapped child token. + +The bridge is configured with an existing platform Secret containing one +renewable, narrowly scoped issuing token. The Secret is mounted read-only and +read from a file. It is not placed in Compose environment values, command-line +arguments, health responses, or logs. + +## Vault preparation + +Create a token role whose allowed policies are limited to the applications in +this environment. Create a renewable issuing token that can create child tokens +through that role and revoke their accessors, store the token as a platform +Secret, and select that Secret while installing this card. Keep the child-token +and response-wrapping lifetimes short. + +The Catalog allowlist is an additional boundary: a workload request must be a +subset of the comma-separated policies entered during installation. + +## Workload use + +```yaml +version: '2' +services: + application: + image: example/application:v1.0.0 + volumes: + - vault-token:/run/vault:ro + +volumes: + vault-token: + driver: pasturestack-vault-volume + driver_opts: + io.pasturestack.vault.policies: default,application + io.pasturestack.vault.file: token + io.pasturestack.vault.uid: '1000' + io.pasturestack.vault.gid: '1000' + io.pasturestack.vault.mode: '0400' + per_container: true +``` + +The file contains a response-wrapping token, not the issuing token or an +unwrapped child token. The application unwraps it once through the Vault API. +After the final workload consumer releases the volume, the driver asks the +bridge to revoke the child-token accessor and erases the memory-backed volume. + +## Security boundary + +The bridge uses +`ghcr.io/pasturestack/vault-secrets-bridge:v0.1.1`. It runs as UID 65532, +drops all Linux capabilities, uses a read-only root filesystem, and persists +only an encrypted accessor record in its dedicated state volume. + +The driver uses +`ghcr.io/pasturestack/secrets-flexvolume-plugin:v0.2.0`. It drops all +capabilities before adding only `SYS_ADMIN`, `CHOWN`, and `FOWNER` for the +isolated `tmpfs` lifecycle and requested read-only ownership. It does not use +privileged mode, host networking, the host PID namespace, or a +container-engine socket. + +Both images are public and use semantic version tags in Catalog and user +interfaces. Manifest digests remain release-verification evidence and are not +shown as deployment coordinates. + +Source, security details, licensing, and release evidence are available from +the [Vault Secrets Bridge](https://github.com/PastureStack/vault-secrets-bridge) +and [Secret Volume Driver](https://github.com/PastureStack/secrets-flexvolume-plugin) +repositories. + +PastureStack is an independent community effort to preserve, audit, and +modernize the Rancher 1.6 ecosystem. It is not affiliated with or endorsed by +Rancher Labs or SUSE. diff --git a/infra-templates/vault-volume-driver/4/README.zh-TW.md b/infra-templates/vault-volume-driver/4/README.zh-TW.md new file mode 100644 index 000000000..fabfaa43a --- /dev/null +++ b/infra-templates/vault-volume-driver/4/README.zh-TW.md @@ -0,0 +1,70 @@ +# PastureStack Vault 存取權杖磁碟區 + +此基礎架構項目會安裝一個非特權的環境橋接服務,並在每台符合條件的受管 +主機安裝一個主機本機 Docker 磁碟區驅動程式。工作負載提出允許的存取 +政策集合後,驅動程式會以主機身分金鑰簽署要求;橋接服務先確認主機仍為 +作用中,再向 Vault 申請短效且經回應封裝的子權杖。 + +橋接服務使用既有的平台機密資料,其中包含一個可續期且權限範圍最小化的 +發行用權杖。該機密資料以唯讀方式掛載,並由檔案讀取;不會寫入 Compose +環境值、命令列參數、健康狀態回應或日誌。 + +## Vault 事前準備 + +建立一個權杖角色,將其允許的存取政策限制在本環境內的應用程式。接著 +建立一個可續期的發行用權杖;該權杖只能透過此角色建立子權杖及撤銷其 +Accessor。請將權杖存入平台機密資料,並在安裝本卡片時選取該機密資料。 +子權杖與回應封裝的存留時間均應保持精簡。 + +商店允許清單是額外的安全界線:工作負載提出的政策必須是安裝時所填半形 +逗號分隔政策的子集合。 + +## 工作負載使用方式 + +```yaml +version: '2' +services: + application: + image: example/application:v1.0.0 + volumes: + - vault-token:/run/vault:ro + +volumes: + vault-token: + driver: pasturestack-vault-volume + driver_opts: + io.pasturestack.vault.policies: default,application + io.pasturestack.vault.file: token + io.pasturestack.vault.uid: '1000' + io.pasturestack.vault.gid: '1000' + io.pasturestack.vault.mode: '0400' + per_container: true +``` + +檔案內存放的是回應封裝權杖,不是發行用權杖或已解封裝的子權杖。應用程式 +透過 Vault API 解封裝一次即可使用。最後一個工作負載使用者釋放磁碟區後, +驅動程式會要求橋接服務撤銷子權杖 Accessor,並清除記憶體磁碟區。 + +## 安全界線 + +橋接服務使用 +`ghcr.io/pasturestack/vault-secrets-bridge:v0.1.1`。程序以 UID 65532 +執行、移除全部 Linux capabilities、使用唯讀根檔案系統,且只在專用狀態 +磁碟區保存加密後的 Accessor 紀錄。 + +驅動程式使用 +`ghcr.io/pasturestack/secrets-flexvolume-plugin:v0.2.0`。程序先移除全部 +capabilities,再僅加入隔離 `tmpfs` 生命週期及指定唯讀擁有權所需的 +`SYS_ADMIN`、`CHOWN` 與 `FOWNER`。它不使用特權模式、主機網路、主機 +PID 命名空間或容器引擎 Socket。 + +兩個映像皆可公開取得;商店與使用者介面只顯示語意版本標籤。映像資訊摘要 +僅保留於發行驗證證據,不會顯示為部署座標。 + +原始碼、安全性說明、授權與發行證據請參閱 +[Vault 機密資料橋接服務](https://github.com/PastureStack/vault-secrets-bridge) +及 +[機密資料磁碟區驅動程式](https://github.com/PastureStack/secrets-flexvolume-plugin)。 + +PastureStack 是獨立的社群計畫,目的在保存、稽核與現代化 Rancher +1.6 生態系;本計畫與 Rancher Labs 或 SUSE 無隸屬或背書關係。 diff --git a/infra-templates/vault-volume-driver/4/docker-compose.yml b/infra-templates/vault-volume-driver/4/docker-compose.yml new file mode 100644 index 000000000..21c856001 --- /dev/null +++ b/infra-templates/vault-volume-driver/4/docker-compose.yml @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: MIT +version: '2' + +services: + vault-secrets-bridge: + image: ghcr.io/pasturestack/vault-secrets-bridge:v0.1.2 + read_only: true + cap_drop: + - ALL + tmpfs: + - /tmp:rw,noexec,nosuid,nodev,size=16m + security_opt: + - 'no-new-privileges:true' + environment: + VAULT_ADDR: '${VAULT_URL}' + VAULT_ROLE: '${VAULT_ROLE}' + PASTURESTACK_VAULT_ALLOWED_POLICIES: '${VAULT_ALLOWED_POLICIES}' + PASTURESTACK_VAULT_ISSUER_TOKEN_FILE: '/run/secrets/{{.Values.ISSUING_TOKEN_SECRET}}' + secrets: + - "{{.Values.ISSUING_TOKEN_SECRET}}" + volumes: + - vault-secrets-bridge-state:/var/lib/pasturestack/vault-secrets-bridge + labels: + io.pasturestack.component: vault-secrets-bridge + io.rancher.container.agent.role: environment + io.rancher.container.create_agent: 'true' + io.rancher.container.dns: 'true' + cpu_shares: 128 + mem_limit: 64m + logging: + driver: json-file + options: + max-size: 10m + max-file: '2' + + vault-volume-driver: + image: ghcr.io/pasturestack/secrets-flexvolume-plugin:v0.2.1 + environment: + PASTURESTACK_SECRET_PROVIDER: vault + PASTURESTACK_SECRET_DRIVER_NAME: pasturestack-vault-volume + PASTURESTACK_SECRET_SOCKET: /run/docker/plugins/pasturestack-vault-volume.sock + PASTURESTACK_SECRET_VOLUME_ROOT: /var/lib/pasturestack/volumes/vault-volume + PASTURESTACK_SECRET_HEALTH_LISTEN: 0.0.0.0:8094 + PASTURESTACK_VAULT_BRIDGE_URL: http://vault-secrets-bridge:8080 + cap_drop: + - ALL + cap_add: + - SYS_ADMIN + - CHOWN + - FOWNER + read_only: true + tmpfs: + - /tmp:rw,noexec,nosuid,nodev,size=16m + security_opt: + - 'apparmor:unconfined' + - 'no-new-privileges:true' + links: + - vault-secrets-bridge:vault-secrets-bridge + labels: + io.pasturestack.component: vault-volume-driver + io.rancher.scheduler.global: 'true' + io.rancher.container.dns: 'true' + volumes: + - /run/docker/plugins:/run/docker/plugins + - /var/lib/pasturestack/volumes:/var/lib/pasturestack/volumes:shared + - /var/lib/rancher/etc/ssl/host.key:/var/lib/pasturestack/etc/ssl/host.key:ro + cpu_shares: 128 + mem_limit: 96m + logging: + driver: json-file + options: + max-size: 10m + max-file: '2' + +volumes: + vault-secrets-bridge-state: + driver: local + +secrets: + "{{.Values.ISSUING_TOKEN_SECRET}}": + external: true diff --git a/infra-templates/vault-volume-driver/4/rancher-compose.yml b/infra-templates/vault-volume-driver/4/rancher-compose.yml new file mode 100644 index 000000000..405a23ea6 --- /dev/null +++ b/infra-templates/vault-volume-driver/4/rancher-compose.yml @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: MIT +.catalog: + name: PastureStack Vault Volume + version: v0.2.2 + description: Deliver response-wrapped, short-lived Vault tokens through host-authenticated read-only volumes. + minimum_rancher_version: v1.6.15-rc1 + labels: + io.pasturestack.catalog.question.vault_url.label.zh-tw: 'Vault API 網址' + io.pasturestack.catalog.question.vault_url.description.zh-tw: 'Vault API 的 HTTPS 基底網址;隔離網路亦可使用內部 HTTP 端點。' + io.pasturestack.catalog.question.vault_role.label.zh-tw: 'Vault 權杖角色' + io.pasturestack.catalog.question.vault_role.description.zh-tw: '發行用權杖透過此角色建立短效子權杖。' + io.pasturestack.catalog.question.vault_allowed_policies.label.zh-tw: '允許的 Vault 存取政策' + io.pasturestack.catalog.question.vault_allowed_policies.description.zh-tw: '工作負載磁碟區可要求的存取政策允許清單,以半形逗號分隔。' + io.pasturestack.catalog.question.issuing_token_secret.label.zh-tw: 'Vault 發行用權杖機密資料' + io.pasturestack.catalog.question.issuing_token_secret.description.zh-tw: '既有平台機密資料,內容為可續期且權限範圍最小化的 Vault 發行用權杖。' + questions: + - variable: VAULT_URL + label: Vault API URL + description: HTTPS Vault API base URL, or a private HTTP endpoint for an isolated network. + type: string + required: true + - variable: VAULT_ROLE + label: Vault token role + description: Token role used by the issuing token to create short-lived child tokens. + type: string + required: true + - variable: VAULT_ALLOWED_POLICIES + label: Allowed Vault policies + description: Comma-separated allowlist of policies that workload volumes may request. + type: string + default: default + required: true + - variable: ISSUING_TOKEN_SECRET + label: Vault issuing-token Secret + description: Existing platform Secret containing one renewable, narrowly scoped Vault issuing token. + type: secret + required: true + +vault-secrets-bridge: + scale: 1 + start_on_create: true + health_check: + request_line: GET /readyz HTTP/1.0 + port: 8080 + interval: 10000 + initializing_timeout: 120000 + reinitializing_timeout: 120000 + response_timeout: 3000 + healthy_threshold: 2 + unhealthy_threshold: 3 + strategy: none + +vault-volume-driver: + storage_driver: + name: pasturestack-vault-volume + description: Host-authenticated, response-wrapped Vault token volumes + scope: local + volume_access_mode: singleHostRW + start_on_create: true + health_check: + request_line: GET /readyz HTTP/1.0 + port: 8094 + interval: 10000 + initializing_timeout: 120000 + reinitializing_timeout: 120000 + response_timeout: 3000 + healthy_threshold: 2 + unhealthy_threshold: 3 + strategy: none diff --git a/infra-templates/vault-volume-driver/config.yml b/infra-templates/vault-volume-driver/config.yml index a77aa445e..f7f882982 100644 --- a/infra-templates/vault-volume-driver/config.yml +++ b/infra-templates/vault-volume-driver/config.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT name: Vault Volume description: Deliver response-wrapped, short-lived Vault tokens through host-authenticated read-only volumes. -version: v0.2.1 +version: v0.2.2 category: Storage maintainer: PastureStack contributors license: MIT template; Apache-2.0 images and bundled dependency licenses apply diff --git a/infra-templates/windows-container-networking/3/README.md b/infra-templates/windows-container-networking/3/README.md new file mode 100644 index 000000000..44dc579c5 --- /dev/null +++ b/infra-templates/windows-container-networking/3/README.md @@ -0,0 +1,31 @@ + + +# PastureStack Windows Container Networking + +This infrastructure entry defines the `nat` and `transparent` Docker network +drivers consumed by compatible Windows container workloads. Install it before +PastureStack Windows Network Services. + +PastureStack is an independent community effort to preserve, audit, and modernize the Rancher 1.6 ecosystem. It is not affiliated with or endorsed by Rancher Labs or SUSE. + +## Compatibility boundary + +The Compose services are selector-only resources; the referenced pause image +is required by the legacy service schema but is not launched as a Windows +workload. The `io.rancher.service.selector.container` key and its historical +selector value are retained solely as control-protocol identifiers for +existing Windows agents. They are not user-facing branding and must be removed +only together with a replacement Windows agent contract. + +## Validation status + +The template parses through the reviewed Catalog Service and is restricted to +the Windows orchestration mode. No Windows host was available for an +end-to-end network-driver gate, so this entry remains a release candidate. + +## License and provenance + +The template files are MIT-licensed PastureStack contributions. The +selector-only placeholder image and bundled dependencies retain their +respective licenses and notices. The preserved Git history retains the +upstream Windows template provenance and authorship. diff --git a/infra-templates/windows-container-networking/3/README.zh-TW.md b/infra-templates/windows-container-networking/3/README.zh-TW.md new file mode 100644 index 000000000..b27a4bfa1 --- /dev/null +++ b/infra-templates/windows-container-networking/3/README.zh-TW.md @@ -0,0 +1,16 @@ + + +# PastureStack Windows 容器網路 + +此基礎架構項目會定義相容 Windows 容器工作負載使用的 `nat` 與 `transparent` +Docker 網路驅動程式。請在 PastureStack Windows 網路服務之前安裝。 + +PastureStack 是獨立的社群計畫,目的在保存、稽核與現代化 Rancher 1.6 +生態系;本計畫與 Rancher Labs 或 SUSE 無隸屬或背書關係。 + +Compose 服務只用來選取既有 Windows 代理程式;相容服務結構雖然要求提供映像, +但不會將該映像當成 Windows 工作負載啟動。歷史選取值僅屬控制協定識別值, +不能在尚未同步更換 Windows 代理程式契約前單獨移除。 + +此範本已通過 Catalog Service 解析,並限制於 Windows 協調模式。由於目前沒有 +Windows 主機完成網路驅動程式的端對端驗證,此項目仍屬候選版本。 diff --git a/infra-templates/windows-container-networking/3/docker-compose.yml b/infra-templates/windows-container-networking/3/docker-compose.yml new file mode 100644 index 000000000..4a94ea106 --- /dev/null +++ b/infra-templates/windows-container-networking/3/docker-compose.yml @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: MIT +version: '2' + +services: + windows-nat-network: + image: ghcr.io/pasturestack/pod-pause-image:v3.0.5 + labels: + io.rancher.service.selector.container: experimental-windows-rancher + + windows-transparent-network: + image: ghcr.io/pasturestack/pod-pause-image:v3.0.5 + labels: + io.rancher.service.selector.container: experimental-windows-rancher diff --git a/infra-templates/windows-container-networking/3/rancher-compose.yml b/infra-templates/windows-container-networking/3/rancher-compose.yml new file mode 100644 index 000000000..e1e0490b0 --- /dev/null +++ b/infra-templates/windows-container-networking/3/rancher-compose.yml @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: MIT +version: '2' +.catalog: + name: PastureStack Windows Container Networking + version: v0.1.1 + description: Define NAT and transparent Docker network drivers for compatible Windows container hosts. + minimum_rancher_version: v1.6.15-rc1 + labels: + io.pasturestack.catalog.name.zh-tw: 'PastureStack Windows 容器網路' + io.pasturestack.catalog.description.zh-tw: '為相容的 Windows 容器主機定義 NAT 與透明 Docker 網路驅動程式。' + io.pasturestack.catalog.question.transparent_network_driver_name.label.zh-tw: '透明網路驅動程式名稱' + io.pasturestack.catalog.question.transparent_network_driver_name.description.zh-tw: 'Windows 主機上已設定的透明網路驅動程式名稱。' + questions: + - variable: TRANSPARENT_NETWORK_DRIVER_NAME + label: Transparent network driver name + description: Existing transparent network driver name configured on the Windows host. + type: string + required: true + default: transparent + +services: + windows-nat-network: + network_driver: + name: PastureStack Windows NAT Network + default_network: + name: nat + kind: nat + + windows-transparent-network: + network_driver: + name: PastureStack Windows Transparent Network + default_network: + name: transparent + kind: $TRANSPARENT_NETWORK_DRIVER_NAME diff --git a/infra-templates/windows-container-networking/config.yml b/infra-templates/windows-container-networking/config.yml index 136395809..f5baa935b 100644 --- a/infra-templates/windows-container-networking/config.yml +++ b/infra-templates/windows-container-networking/config.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT name: Windows Container Networking description: Define NAT and transparent Docker network drivers for compatible Windows container hosts. -version: v0.1.0 +version: v0.1.1 category: Networking maintainer: PastureStack contributors license: MIT template; selector-only placeholder image retains its Apache-2.0 and bundled dependency licenses diff --git a/integration/core/test_catalog.py b/integration/core/test_catalog.py index 6bb824103..720f097c7 100644 --- a/integration/core/test_catalog.py +++ b/integration/core/test_catalog.py @@ -197,10 +197,10 @@ def test_catalog_list(): assert by_folder[('infra', 'healthcheck')][ 'name'] == 'Metadata Healthcheck' assert by_folder[('infra', 'healthcheck')][ - 'defaultVersion'] == 'v0.3.16' + 'defaultVersion'] == 'v0.3.17' assert by_folder[('infra', 'healthcheck')][ 'links']['defaultVersion'].endswith( - ':1') + ':2') assert by_folder[('infra', 'ipsec-overlay')]['name'] == ( 'IPsec Overlay') assert by_folder[('infra', 'ipsec-overlay')][ @@ -218,24 +218,24 @@ def test_catalog_list(): assert by_folder[('infra', 'network-diagnostics')]['name'] == ( 'Network Diagnostics') assert by_folder[('infra', 'network-diagnostics')][ - 'defaultVersion'] == 'v0.2.1' + 'defaultVersion'] == 'v0.2.2' assert by_folder[('infra', 'network-diagnostics')][ 'links']['defaultVersion'].endswith( - ':2') + ':3') assert by_folder[('infra', 'network-policy-manager')]['name'] == ( 'Network Policy Manager') assert by_folder[('infra', 'network-policy-manager')][ - 'defaultVersion'] == 'v0.3.3' + 'defaultVersion'] == 'v0.3.4' assert by_folder[('infra', 'network-policy-manager')][ 'links']['defaultVersion'].endswith( - ':3') + ':4') assert by_folder[('infra', 'network-services')]['name'] == ( 'Network Services') assert by_folder[('infra', 'network-services')][ - 'defaultVersion'] == 'v0.3.8' + 'defaultVersion'] == 'v0.3.9' assert by_folder[('infra', 'network-services')][ 'links']['defaultVersion'].endswith( - ':10') + ':11') assert by_folder[('infra', 'nfs-storage')][ 'name'] == 'NFS Storage' assert by_folder[('infra', 'nfs-storage')][ @@ -246,17 +246,17 @@ def test_catalog_list(): assert by_folder[('infra', 'secret-volume-driver')][ 'name'] == 'Secret Volume' assert by_folder[('infra', 'secret-volume-driver')][ - 'defaultVersion'] == 'v0.1.2' + 'defaultVersion'] == 'v0.1.3' assert by_folder[('infra', 'secret-volume-driver')][ 'links']['defaultVersion'].endswith( - ':2') + ':3') assert by_folder[('infra', 'vault-volume-driver')][ 'name'] == 'Vault Volume' assert by_folder[('infra', 'vault-volume-driver')][ - 'defaultVersion'] == 'v0.2.1' + 'defaultVersion'] == 'v0.2.2' assert by_folder[('infra', 'vault-volume-driver')][ 'links']['defaultVersion'].endswith( - ':3') + ':4') assert by_folder[('infra', 'per-host-subnet-network')]['name'] == ( 'Per-Host Subnet Network') assert by_folder[('infra', 'per-host-subnet-network')][ @@ -280,10 +280,10 @@ def test_catalog_list(): assert by_folder[('infra', 'system-image-preloader')]['name'] == ( 'System Image Preloader') assert by_folder[('infra', 'system-image-preloader')][ - 'defaultVersion'] == 'v0.3.0' + 'defaultVersion'] == 'v0.3.1' assert by_folder[('infra', 'system-image-preloader')][ 'links']['defaultVersion'].endswith( - ':2') + ':3') assert by_folder[('infra', 'vxlan-overlay-network')]['name'] == ( 'VXLAN Overlay Network') assert by_folder[('infra', 'vxlan-overlay-network')][ @@ -294,10 +294,10 @@ def test_catalog_list(): assert by_folder[('infra', 'windows-container-networking')][ 'name'] == 'Windows Container Networking' assert by_folder[('infra', 'windows-container-networking')][ - 'defaultVersion'] == 'v0.1.0' + 'defaultVersion'] == 'v0.1.1' assert by_folder[('infra', 'windows-container-networking')][ 'links']['defaultVersion'].endswith( - ':2') + ':3') assert by_folder[('infra', 'windows-ecr-credential-sync')][ 'name'] == 'Windows ECR Credential Sync' assert by_folder[('infra', 'windows-ecr-credential-sync')][ @@ -547,7 +547,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): health_files = health_version['files'] health_docker = health_files['docker-compose.yml'] health_platform = health_files['rancher-compose.yml'] - health_image = 'ghcr.io/pasturestack/metadata-healthcheck:v0.3.16' + health_image = 'ghcr.io/pasturestack/metadata-healthcheck:v0.3.17' assert "version: '2'\nservices:\n healthcheck:" in health_docker assert health_docker.count('image: {}'.format(health_image)) == 1 assert ( @@ -658,9 +658,9 @@ def test_catalog_compose_shapes_are_runtime_compatible(): diagnostics_docker = diagnostics_files['docker-compose.yml.tpl'] diagnostics_platform = diagnostics_files['rancher-compose.yml'] diagnostics_agent_image = ( - 'ghcr.io/pasturestack/network-diagnostics-agent:v0.2.0') + 'ghcr.io/pasturestack/network-diagnostics-agent:v0.2.1') diagnostics_service_image = ( - 'ghcr.io/pasturestack/network-diagnostics-service:v0.2.0') + 'ghcr.io/pasturestack/network-diagnostics-service:v0.2.1') assert diagnostics_docker.count( 'image: {}'.format(diagnostics_agent_image)) == 1 assert diagnostics_docker.count( @@ -697,7 +697,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): policy_docker = policy_files['docker-compose.yml'] policy_platform = policy_files['rancher-compose.yml'] policy_image = ( - 'ghcr.io/pasturestack/network-policy-manager:v0.3.1') + 'ghcr.io/pasturestack/network-policy-manager:v0.3.2') assert policy_docker.count( 'image: {}'.format(policy_image)) == 1 assert '\n network-policy-manager:\n' in policy_docker @@ -725,9 +725,9 @@ def test_catalog_compose_shapes_are_runtime_compatible(): network_docker = network_files['docker-compose.yml.tpl'] network_platform = network_files['rancher-compose.yml'] network_manager_image = ( - 'ghcr.io/pasturestack/network-plugin-manager:v0.8.22') - metadata_image = 'ghcr.io/pasturestack/metadata-service:v0.9.11' - dns_image = 'ghcr.io/pasturestack/internal-dns:v0.17.11' + 'ghcr.io/pasturestack/network-plugin-manager:v0.8.23') + metadata_image = 'ghcr.io/pasturestack/metadata-service:v0.10.5' + dns_image = 'ghcr.io/pasturestack/internal-dns:v0.17.13' assert network_docker.count( 'image: {}'.format(network_manager_image)) == 1 assert network_docker.count('image: {}'.format(metadata_image)) == 1 @@ -790,7 +790,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): secret_docker = secret_files['docker-compose.yml'] secret_platform = secret_files['rancher-compose.yml'] secret_image = ( - 'ghcr.io/pasturestack/secrets-flexvolume-plugin:v0.1.1') + 'ghcr.io/pasturestack/secrets-flexvolume-plugin:v0.2.1') assert secret_docker.count('image: {}'.format(secret_image)) == 1 assert '\n secret-volume-driver:\n' in secret_docker assert 'privileged:' not in secret_docker @@ -843,9 +843,9 @@ def test_catalog_compose_shapes_are_runtime_compatible(): 'issuing_token_secret.label.zh-tw' ] == 'Vault 發行用權杖機密資料' vault_bridge_image = ( - 'ghcr.io/pasturestack/vault-secrets-bridge:v0.1.1') + 'ghcr.io/pasturestack/vault-secrets-bridge:v0.1.2') vault_driver_image = ( - 'ghcr.io/pasturestack/secrets-flexvolume-plugin:v0.2.0') + 'ghcr.io/pasturestack/secrets-flexvolume-plugin:v0.2.1') assert vault_docker.count( 'image: {}'.format(vault_bridge_image)) == 1 assert vault_docker.count( @@ -968,7 +968,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): preloader_docker = preloader_files['docker-compose.yml.tpl'] preloader_platform = preloader_files['rancher-compose.yml'] preloader_image = ( - 'ghcr.io/pasturestack/system-image-preloader:v0.3.0') + 'ghcr.io/pasturestack/system-image-preloader:v0.3.1') assert preloader_docker.count( 'image: {}'.format(preloader_image)) == 1 assert '\n system-image-preloader:\n' in preloader_docker @@ -982,7 +982,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): assert '{{- if' not in preloader_docker assert '{{- end' not in preloader_docker assert '@sha256:' not in preloader_docker - assert 'ghcr.io/pasturestack/system-image-preloader:v0.3.0' in ( + assert 'ghcr.io/pasturestack/system-image-preloader:v0.3.1' in ( preloader_docker) assert 'default: v1.6.282' in preloader_platform assert 'default: false' in preloader_platform @@ -1062,7 +1062,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): windows_container_network_files['rancher-compose.yml']) selector_image = ( 'ghcr.io/pasturestack/pod-pause-image:' - 'v3.0.2') + 'v3.0.5') assert windows_container_network_docker.count( 'image: {}'.format(selector_image)) == 2 assert windows_container_network_docker.count( @@ -1093,6 +1093,130 @@ def test_catalog_compose_shapes_are_runtime_compatible(): assert '.catalog:\n name: PastureStack Native' in project_platform +@pytest.mark.parametrize( + 'template,old_number,new_number,old_version,new_version,replacements', [ + ( + 'network-diagnostics', '2', '3', + 'v0.2.1', 'v0.2.2', [ + ( + 'network-diagnostics-agent:v0.2.0', + 'network-diagnostics-agent:v0.2.1', + ), + ( + 'network-diagnostics-service:v0.2.0', + 'network-diagnostics-service:v0.2.1', + ), + ], + ), + ( + 'healthcheck', '1', '2', + 'v0.3.16', 'v0.3.17', [ + ( + 'metadata-healthcheck:v0.3.16', + 'metadata-healthcheck:v0.3.17', + ), + ], + ), + ( + 'secret-volume-driver', '2', '3', + 'v0.1.2', 'v0.1.3', [ + ( + 'secrets-flexvolume-plugin:v0.1.1', + 'secrets-flexvolume-plugin:v0.2.1', + ), + ], + ), + ( + 'vault-volume-driver', '3', '4', + 'v0.2.1', 'v0.2.2', [ + ( + 'vault-secrets-bridge:v0.1.1', + 'vault-secrets-bridge:v0.1.2', + ), + ( + 'secrets-flexvolume-plugin:v0.2.0', + 'secrets-flexvolume-plugin:v0.2.1', + ), + ], + ), + ( + 'windows-container-networking', '2', '3', + 'v0.1.0', 'v0.1.1', [ + ( + 'pod-pause-image:v3.0.2', + 'pod-pause-image:v3.0.5', + ), + ], + ), + ( + 'network-policy-manager', '3', '4', + 'v0.3.3', 'v0.3.4', [ + ( + 'network-policy-manager:v0.3.1', + 'network-policy-manager:v0.3.2', + ), + ], + ), + ( + 'system-image-preloader', '2', '3', + 'v0.3.0', 'v0.3.1', [ + ( + 'system-image-preloader:v0.3.0', + 'system-image-preloader:v0.3.1', + ), + ], + ), + ( + 'network-services', '10', '11', + 'v0.3.8', 'v0.3.9', [ + ( + 'network-plugin-manager:v0.8.22', + 'network-plugin-manager:v0.8.23', + ), + ( + 'metadata-service:v0.9.11', + 'metadata-service:v0.10.5', + ), + ( + 'internal-dns:v0.17.11', + 'internal-dns:v0.17.13', + ), + ], + ), + ]) +def test_october_security_revisions_preserve_contract( + template, old_number, new_number, old_version, new_version, + replacements): + prefix = 'infra-templates/' + template + '/' + for filename in ('docker-compose.yml', 'docker-compose.yml.tpl'): + old_path = _file(prefix + old_number + '/' + filename) + if not os.path.isfile(old_path): + continue + with open(old_path, encoding='utf-8') as source: + expected = source.read() + for old_image, new_image in replacements: + expected = expected.replace(old_image, new_image) + with open(_file(prefix + new_number + '/' + filename), + encoding='utf-8') as source: + assert source.read() == expected + for filename in ('rancher-compose.yml', 'README.md', 'README.zh-TW.md'): + with open(_file(prefix + old_number + '/' + filename), + encoding='utf-8') as source: + expected = source.read() + if filename == 'rancher-compose.yml': + expected = expected.replace( + ' version: ' + old_version + '\n', + ' version: ' + new_version + '\n') + with open(_file(prefix + new_number + '/' + filename), + encoding='utf-8') as source: + assert source.read() == expected + for number in (old_number, new_number): + retained = _get_json(_catalog_url( + '/v1-catalog/templateversions/{}:infra*{}:{}'.format( + _catalog_name(), template, number))) + assert 'rancher-compose.yml' in retained['files'] + + def test_catalog_commit_is_pinned(): catalogs = _get_json(_catalog_url('/v1-catalog/catalogs')) data = catalogs.get('data', []) diff --git a/scripts/audit_deployable_images.py b/scripts/audit_deployable_images.py index 4cea6ff20..f778bf820 100644 --- a/scripts/audit_deployable_images.py +++ b/scripts/audit_deployable_images.py @@ -52,17 +52,20 @@ ) RETAINED_VERSION_LAYOUTS = { "ecr-credential-sync": ("2", "3"), - "healthcheck": ("0", "1"), + "healthcheck": ("0", "1", "2"), "ipsec-overlay": ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"), "layer-2-flat-network": ("2", "3", "4", "5", "6"), - "network-diagnostics": ("1", "2"), - "network-policy-manager": ("1", "2", "3"), - "network-services": ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10"), + "network-diagnostics": ("1", "2", "3"), + "network-policy-manager": ("1", "2", "3", "4"), + "network-services": ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"), "nfs-storage": ("1", "2"), "per-host-subnet-network": ("2", "3", "4"), "resource-scheduler": ("1", "2", "3", "4", "5"), - "secret-volume-driver": ("1", "2"), + "secret-volume-driver": ("1", "2", "3"), + "system-image-preloader": ("2", "3"), + "vault-volume-driver": ("3", "4"), "vxlan-overlay-network": ("2", "3", "4", "5"), + "windows-container-networking": ("2", "3"), } RETAINED_VERSION_HASHES = { "infra-templates/healthcheck/0/README.md": "1b18863d98ba3c042676f81daf6d6fc510c255cd1df275495985ed41f3b13aaa", From 1b9139865f01ea5eb0f9fc0562b99a348b4fc53d Mon Sep 17 00:00:00 2001 From: chen21019 <19357113+chen21019@users.noreply.github.com> Date: Fri, 23 Oct 2026 21:41:39 +0800 Subject: [PATCH 04/10] Add retained Route 53 revision for verified external DNS release --- catalog-images.json | 23 ++++ infra-templates/route53-dns-sync/3/README.md | 86 ++++++++++++ .../route53-dns-sync/3/README.zh-TW.md | 84 ++++++++++++ .../route53-dns-sync/3/docker-compose.yml.tpl | 34 +++++ .../route53-dns-sync/3/rancher-compose.yml | 125 ++++++++++++++++++ infra-templates/route53-dns-sync/config.yml | 2 +- integration/core/test_catalog.py | 15 ++- scripts/audit_deployable_images.py | 1 + 8 files changed, 366 insertions(+), 4 deletions(-) create mode 100644 infra-templates/route53-dns-sync/3/README.md create mode 100644 infra-templates/route53-dns-sync/3/README.zh-TW.md create mode 100644 infra-templates/route53-dns-sync/3/docker-compose.yml.tpl create mode 100644 infra-templates/route53-dns-sync/3/rancher-compose.yml diff --git a/catalog-images.json b/catalog-images.json index 71dad76ff..9d4737676 100644 --- a/catalog-images.json +++ b/catalog-images.json @@ -1207,6 +1207,29 @@ "source": "component owner verified anonymous manifest/config readback", "workflowRun": "https://github.com/PastureStack/system-image-preloader/actions/runs/39958486019" } + }, + { + "sourceRepository": "https://github.com/PastureStack/external-dns-sync", + "sourcePath": "package/Dockerfile", + "registryPage": "https://github.com/orgs/PastureStack/packages/container/package/external-dns-sync", + "licenseBoundary": "Apache-2.0 source and image; bundled Ubuntu and vendored Go dependencies retain their upstream licenses and notices", + "platforms": [ + "linux/amd64" + ], + "reference": "ghcr.io/pasturestack/external-dns-sync:v0.8.1", + "sourceCommit": "7ff253bd84c13fd6748b9ca9737370de9ff5535f", + "manifestDigest": "sha256:0dd0a346573f1661abf920a0d87a153a312515882b16a8ef5983614fa725c751", + "reviewedAt": "2026-10-23", + "vulnerabilityScan": { + "scope": "published runtime image", + "high": 0, + "critical": 0, + "evidence": "https://github.com/PastureStack/external-dns-sync/actions/runs/39960962858" + }, + "publicationVerification": { + "source": "component owner verified anonymous manifest/config readback", + "workflowRun": "https://github.com/PastureStack/external-dns-sync/actions/runs/39960962858" + } } ] } diff --git a/infra-templates/route53-dns-sync/3/README.md b/infra-templates/route53-dns-sync/3/README.md new file mode 100644 index 000000000..02128fc82 --- /dev/null +++ b/infra-templates/route53-dns-sync/3/README.md @@ -0,0 +1,86 @@ +# PastureStack Route 53 DNS Sync + +> PastureStack is an independent community effort to preserve, audit, and modernize the Rancher 1.6 ecosystem. It is not affiliated with or endorsed by Rancher Labs or SUSE. + +This infrastructure template synchronizes service addresses from one compatible +environment to an existing Amazon Route 53 hosted zone. + +- Image: `ghcr.io/pasturestack/external-dns-sync:v0.8.0` +- Source: [`PastureStack/external-dns-sync@v0.8.0`](https://github.com/PastureStack/external-dns-sync/tree/v0.8.0) +- Upstream: [`rancher-archives/external-dns`](https://github.com/rancher-archives/external-dns) + +The image reference always uses the semantic release tag. Published Catalog +manifests do not expose an image digest because long digest text breaks the +legacy service interface. Release validation records immutable identity +separately. + +## DNS behavior + +The default A-record name is: + +```text +... +``` + +The service also maintains one ownership TXT record. It uses that record to +update or remove only the A records it owns. Existing unrelated records in the +hosted zone are not managed. + +The current compatible control plane injects environment-scoped API +credentials through its agent-role protocol. The runtime maps those values to +the neutral PastureStack API contract. A reviewed host CA file can optionally +be mounted read-only when a private certificate authority is required. + +## AWS permissions + +Use an IAM role whenever practical. Otherwise, create a dedicated access key +with permissions limited to the hosted zone used by this stack. The minimum +API actions are: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "route53:GetHostedZone", + "route53:GetHostedZoneCount", + "route53:ListHostedZonesByName", + "route53:ListResourceRecordSets" + ], + "Resource": "*" + }, + { + "Effect": "Allow", + "Action": "route53:ChangeResourceRecordSets", + "Resource": "arn:aws:route53:::hostedzone/" + } + ] +} +``` + +Replace `` with the selected zone. Do not commit credentials or +include them in issue reports, screenshots, or diagnostic logs. + +## Upgrade compatibility + +Neutral PastureStack DNS policy labels take precedence. The runtime also reads +the four documented historical service and host label identifiers so existing +workloads retain their DNS policy during an in-place upgrade. See the runtime +repository's `COMPATIBILITY.md` for the exact bounded protocol surface. + +Only one active DNS Sync instance should manage a given environment and hosted +zone combination. Before changing the TTL during an upgrade from a pre-0.6 +runtime, complete the runtime upgrade first and change the TTL in a second +operation. + +## Runtime boundary + +The container runs as UID/GID `10001:10001`. It does not use privileged mode, +host networking, a Docker socket, or writable host storage. Its dependency-aware +health endpoint is available only on container port `10000`. + +The template is MIT-licensed. External DNS Sync remains Apache-2.0, and its +bundled dependencies retain their own licenses and notices. Upstream Git +history and authorship are preserved in the source repository. diff --git a/infra-templates/route53-dns-sync/3/README.zh-TW.md b/infra-templates/route53-dns-sync/3/README.zh-TW.md new file mode 100644 index 000000000..8c8b6090a --- /dev/null +++ b/infra-templates/route53-dns-sync/3/README.zh-TW.md @@ -0,0 +1,84 @@ +# PastureStack Route 53 DNS 紀錄同步 + +> PastureStack 是獨立的社群計畫,目的在保存、稽核與現代化 Rancher +> 1.6 生態系;本計畫與 Rancher Labs 或 SUSE 無隸屬或背書關係。 + +此基礎架構範本會把相容環境的服務位址同步到既有的 Amazon Route 53 +託管區域。 + +- 映像:`ghcr.io/pasturestack/external-dns-sync:v0.8.0` +- 原始碼: + [`PastureStack/external-dns-sync@v0.8.0`](https://github.com/PastureStack/external-dns-sync/tree/v0.8.0) +- 上游: + [`rancher-archives/external-dns`](https://github.com/rancher-archives/external-dns) + +映像一律使用語意化版本標籤。公開商店資訊不顯示映像摘要,以免過長的 +摘要文字破壞舊版服務介面;不可變更的映像識別資料會另行保留在發布 +驗證證據中。 + +## DNS 行為 + +預設 A 紀錄名稱如下: + +```text +<服務>.<堆疊>.<環境>.<託管區域> +``` + +服務也會維護一筆所有權 TXT 紀錄,並利用該紀錄只更新或移除自己建立 +的 A 紀錄,不會管理託管區域內其他既有紀錄。 + +相容控制平面會透過代理程式角色協定注入環境範圍的 API 登入資訊。 +執行環境會把這些值映射到中性的 PastureStack API 契約。若環境使用 +私有憑證授權單位,可選擇以唯讀方式掛載經審核的主機 CA 檔案。 + +## AWS 權限 + +建議優先使用 IAM 角色。若必須使用存取金鑰,請建立專用金鑰,並把 +權限限制在此堆疊使用的託管區域。最低 API 權限如下: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "route53:GetHostedZone", + "route53:GetHostedZoneCount", + "route53:ListHostedZonesByName", + "route53:ListResourceRecordSets" + ], + "Resource": "*" + }, + { + "Effect": "Allow", + "Action": "route53:ChangeResourceRecordSets", + "Resource": "arn:aws:route53:::hostedzone/" + } + ] +} +``` + +請以選取的區域識別碼取代 ``。請勿提交登入資訊, +也不要把登入資訊放入問題回報、螢幕擷取畫面或診斷日誌。 + +## 升級相容性 + +中性的 PastureStack DNS 政策標籤具有較高優先順序。執行環境仍會 +讀取四個已記錄的歷史服務與主機標籤,確保既有工作負載就地升級時保留 +DNS 政策。精確且有範圍限制的協定介面請參閱執行專案的 +`COMPATIBILITY.md`。 + +同一組環境與託管區域只能由一個執行中的 DNS 同步服務管理。從 +0.6 以前版本升級並變更 TTL 時,請先完成執行環境升級,再以第二次 +操作變更 TTL。 + +## 執行界線 + +容器以 UID/GID `10001:10001` 執行,不使用特權模式、主機網路、 +Docker Socket 或可寫入的主機儲存空間。會感知相依服務狀態的健康 +端點只在容器連接埠 `10000` 提供。 + +範本採 MIT 授權。External DNS Sync 保留 Apache-2.0 授權,隨附 +相依套件保留各自的授權及聲明。原始碼儲存庫保留上游 Git 歷史及 +作者資訊。 diff --git a/infra-templates/route53-dns-sync/3/docker-compose.yml.tpl b/infra-templates/route53-dns-sync/3/docker-compose.yml.tpl new file mode 100644 index 000000000..bcd4c26b5 --- /dev/null +++ b/infra-templates/route53-dns-sync/3/docker-compose.yml.tpl @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: MIT +version: '2' +services: + route53-dns-sync: + image: ghcr.io/pasturestack/external-dns-sync:v0.8.1 + command: + - -provider=route53 + expose: + - '10000' + environment: + AWS_ACCESS_KEY_ID: '${AWS_ACCESS_KEY_ID}' + AWS_REGION: '${AWS_REGION}' + AWS_SECRET_ACCESS_KEY: '${AWS_SECRET_ACCESS_KEY}' + AWS_SESSION_TOKEN: '${AWS_SESSION_TOKEN}' + NAME_TEMPLATE: '${NAME_TEMPLATE}' + ROOT_DOMAIN: '${ROOT_DOMAIN}' + ROUTE53_MAX_RETRIES: '${ROUTE53_MAX_RETRIES}' + ROUTE53_ZONE_ID: '${ROUTE53_ZONE_ID}' + TTL: '${TTL}' + labels: + io.pasturestack.component: route53-dns-sync + io.rancher.container.create_agent: 'true' + io.rancher.container.agent.role: external-dns + {{ if eq .Values.MOUNT_PLATFORM_CA "true"}} + volumes: + - ${PLATFORM_CA_FILE}:/var/lib/pasturestack/etc/ssl/ca.crt:ro + {{ end}} + cpu_shares: 128 + mem_limit: 128m + logging: + driver: json-file + options: + max-size: 10m + max-file: '2' diff --git a/infra-templates/route53-dns-sync/3/rancher-compose.yml b/infra-templates/route53-dns-sync/3/rancher-compose.yml new file mode 100644 index 000000000..82787e588 --- /dev/null +++ b/infra-templates/route53-dns-sync/3/rancher-compose.yml @@ -0,0 +1,125 @@ +# SPDX-License-Identifier: MIT +version: '2' +.catalog: + name: PastureStack Route 53 DNS Sync + version: v0.8.1 + description: Synchronize compatible environment service addresses to an Amazon Route 53 hosted zone. + minimum_rancher_version: v1.6.13-rc1 + labels: + io.pasturestack.catalog.question.aws_region.label.zh-tw: 'AWS 區域' + io.pasturestack.catalog.question.aws_region.description.zh-tw: 'AWS 要求籤章使用的區域;請使用 AWS 帳戶設定的區域。' + io.pasturestack.catalog.question.aws_access_key_id.label.zh-tw: 'AWS 存取金鑰識別碼' + io.pasturestack.catalog.question.aws_access_key_id.description.zh-tw: '由 EC2 IAM 角色提供登入資訊時可留空。' + io.pasturestack.catalog.question.aws_secret_access_key.label.zh-tw: 'AWS 私密存取金鑰' + io.pasturestack.catalog.question.aws_secret_access_key.description.zh-tw: '與 AWS 存取金鑰識別碼配對的私密金鑰。' + io.pasturestack.catalog.question.aws_session_token.label.zh-tw: 'AWS 工作階段權杖' + io.pasturestack.catalog.question.aws_session_token.description.zh-tw: '使用 AWS 臨時登入資訊時提供的選用權杖。' + io.pasturestack.catalog.question.root_domain.label.zh-tw: '託管區域名稱' + io.pasturestack.catalog.question.root_domain.description.zh-tw: '既有 Route 53 託管區域名稱,例如 example.com。' + io.pasturestack.catalog.question.route53_zone_id.label.zh-tw: '託管區域識別碼' + io.pasturestack.catalog.question.route53_zone_id.description.zh-tw: '選填;若有多個同名託管區域則為必填。' + io.pasturestack.catalog.question.name_template.label.zh-tw: 'DNS 名稱範本' + io.pasturestack.catalog.question.name_template.description.zh-tw: '選用的紀錄名稱範本;留空時使用服務、堆疊與環境名稱。' + io.pasturestack.catalog.question.ttl.label.zh-tw: 'DNS 紀錄存留時間' + io.pasturestack.catalog.question.ttl.description.zh-tw: '資源紀錄可快取的秒數。' + io.pasturestack.catalog.question.route53_max_retries.label.zh-tw: 'Route 53 重試次數上限' + io.pasturestack.catalog.question.route53_max_retries.description.zh-tw: 'Route 53 要求遭限流或暫時失敗時的重試次數上限。' + io.pasturestack.catalog.question.mount_platform_ca.label.zh-tw: '掛載平台 CA 憑證' + io.pasturestack.catalog.question.mount_platform_ca.description.zh-tw: '相容環境 API 使用私有憑證授權單位時,掛載經審核的主機 CA 檔案。' + io.pasturestack.catalog.question.platform_ca_file.label.zh-tw: '平台 CA 憑證路徑' + io.pasturestack.catalog.question.platform_ca_file.description.zh-tw: 'PEM 格式 CA 憑證的主機絕對路徑;只有啟用掛載時才會使用。' + io.pasturestack.catalog.question.health_check_interval.label.zh-tw: '健康檢查間隔' + io.pasturestack.catalog.question.health_check_interval.description.zh-tw: '兩次相依服務感知健康檢查之間的毫秒數。' + questions: + - variable: AWS_REGION + label: AWS region + description: AWS signing region; use the region configured for your AWS account. + type: string + default: us-east-1 + required: true + - variable: AWS_ACCESS_KEY_ID + label: AWS access key ID + description: Optional when an EC2 IAM role supplies credentials. + type: string + default: '' + required: false + - variable: AWS_SECRET_ACCESS_KEY + label: AWS secret access key + description: Secret paired with the AWS access key ID. + type: password + default: '' + required: false + - variable: AWS_SESSION_TOKEN + label: AWS session token + description: Optional token for temporary AWS credentials. + type: password + default: '' + required: false + - variable: ROOT_DOMAIN + label: Hosted zone name + description: Existing Route 53 hosted-zone name, such as example.com. + type: string + default: '' + required: true + - variable: ROUTE53_ZONE_ID + label: Hosted zone ID + description: Optional hosted-zone ID; required when more than one zone has the same name. + type: string + default: '' + required: false + - variable: NAME_TEMPLATE + label: DNS name template + description: Optional record-name template; blank uses service, stack, and environment names. + type: string + default: '' + required: false + - variable: TTL + label: DNS record TTL + description: Resource-record cache time in seconds. + type: int + min: 1 + max: 86400 + default: 60 + required: true + - variable: ROUTE53_MAX_RETRIES + label: Maximum Route 53 retries + description: Retry limit for throttled or transient Route 53 requests. + type: int + min: 0 + max: 10 + default: 3 + required: true + - variable: MOUNT_PLATFORM_CA + label: Mount a platform CA certificate + description: Mount a reviewed host CA file when the compatible environment API uses a private certificate authority. + type: boolean + default: false + required: true + - variable: PLATFORM_CA_FILE + label: Platform CA certificate path + description: Absolute host path of the PEM-encoded CA certificate; used only when mounting is enabled. + type: string + default: /var/lib/pasturestack/etc/ssl/ca.crt + required: true + - variable: HEALTH_CHECK_INTERVAL + label: Health check interval + description: Milliseconds between dependency-aware health checks. + type: int + min: 2000 + max: 60000 + default: 10000 + required: true + +route53-dns-sync: + scale: 1 + start_on_create: true + health_check: + request_line: GET /ping HTTP/1.0 + port: 10000 + interval: ${HEALTH_CHECK_INTERVAL} + initializing_timeout: 60000 + reinitializing_timeout: 60000 + response_timeout: 8000 + healthy_threshold: 2 + unhealthy_threshold: 3 + strategy: none diff --git a/infra-templates/route53-dns-sync/config.yml b/infra-templates/route53-dns-sync/config.yml index a63e41982..f728bb707 100644 --- a/infra-templates/route53-dns-sync/config.yml +++ b/infra-templates/route53-dns-sync/config.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT name: Route 53 DNS Sync description: Synchronize compatible environment service addresses to an Amazon Route 53 hosted zone. -version: v0.8.0 +version: v0.8.1 category: External DNS maintainer: PastureStack contributors license: MIT template; Apache-2.0 image and bundled dependency licenses apply diff --git a/integration/core/test_catalog.py b/integration/core/test_catalog.py index 720f097c7..c127587ed 100644 --- a/integration/core/test_catalog.py +++ b/integration/core/test_catalog.py @@ -273,10 +273,10 @@ def test_catalog_list(): assert by_folder[('infra', 'route53-dns-sync')][ 'name'] == 'Route 53 DNS Sync' assert by_folder[('infra', 'route53-dns-sync')][ - 'defaultVersion'] == 'v0.8.0' + 'defaultVersion'] == 'v0.8.1' assert by_folder[('infra', 'route53-dns-sync')][ 'links']['defaultVersion'].endswith( - ':2') + ':3') assert by_folder[('infra', 'system-image-preloader')]['name'] == ( 'System Image Preloader') assert by_folder[('infra', 'system-image-preloader')][ @@ -938,7 +938,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): route53_files = route53_version['files'] route53_docker = route53_files['docker-compose.yml.tpl'] route53_platform = route53_files['rancher-compose.yml'] - route53_image = 'ghcr.io/pasturestack/external-dns-sync:v0.8.0' + route53_image = 'ghcr.io/pasturestack/external-dns-sync:v0.8.1' assert route53_docker.count( 'image: {}'.format(route53_image)) == 1 assert '\n route53-dns-sync:\n' in route53_docker @@ -1166,6 +1166,15 @@ def test_catalog_compose_shapes_are_runtime_compatible(): ), ], ), + ( + 'route53-dns-sync', '2', '3', + 'v0.8.0', 'v0.8.1', [ + ( + 'external-dns-sync:v0.8.0', + 'external-dns-sync:v0.8.1', + ), + ], + ), ( 'network-services', '10', '11', 'v0.3.8', 'v0.3.9', [ diff --git a/scripts/audit_deployable_images.py b/scripts/audit_deployable_images.py index f778bf820..7c5c4303d 100644 --- a/scripts/audit_deployable_images.py +++ b/scripts/audit_deployable_images.py @@ -60,6 +60,7 @@ "network-services": ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"), "nfs-storage": ("1", "2"), "per-host-subnet-network": ("2", "3", "4"), + "route53-dns-sync": ("2", "3"), "resource-scheduler": ("1", "2", "3", "4", "5"), "secret-volume-driver": ("1", "2", "3"), "system-image-preloader": ("2", "3"), From af6dadb9249df73ea27c80859232e5539536c5dd Mon Sep 17 00:00:00 2001 From: chen21019 <19357113+chen21019@users.noreply.github.com> Date: Fri, 23 Oct 2026 21:51:11 +0800 Subject: [PATCH 05/10] Add verified cron and IPsec security revisions --- catalog-images.json | 46 +++++++ .../container-schedule/3/README.md | 47 +++++++ .../container-schedule/3/README.zh-TW.md | 42 +++++++ .../3/docker-compose.yml.tpl | 19 +++ .../container-schedule/3/rancher-compose.yml | 28 +++++ infra-templates/container-schedule/config.yml | 2 +- infra-templates/ipsec-overlay/13/README.md | 36 ++++++ .../ipsec-overlay/13/README.zh-TW.md | 95 +++++++++++++++ .../ipsec-overlay/13/docker-compose.yml.tpl | 115 ++++++++++++++++++ .../ipsec-overlay/13/rancher-compose.yml | 97 +++++++++++++++ infra-templates/ipsec-overlay/config.yml | 2 +- .../layer-2-flat-network/7/README.md | 31 +++++ .../layer-2-flat-network/7/README.zh-TW.md | 26 ++++ .../7/docker-compose.yml.tpl | 70 +++++++++++ .../7/rancher-compose.yml | 96 +++++++++++++++ .../layer-2-flat-network/config.yml | 2 +- .../per-host-subnet-network/5/README.md | 37 ++++++ .../per-host-subnet-network/5/README.zh-TW.md | 35 ++++++ .../5/docker-compose.yml.tpl | 78 ++++++++++++ .../5/rancher-compose.yml | 88 ++++++++++++++ .../per-host-subnet-network/config.yml | 2 +- .../vxlan-overlay-network/6/README.md | 44 +++++++ .../vxlan-overlay-network/6/README.zh-TW.md | 44 +++++++ .../6/docker-compose.yml.tpl | 97 +++++++++++++++ .../6/rancher-compose.yml | 56 +++++++++ .../vxlan-overlay-network/config.yml | 2 +- integration/core/test_catalog.py | 89 ++++++++++---- scripts/audit_deployable_images.py | 9 +- 28 files changed, 1304 insertions(+), 31 deletions(-) create mode 100644 infra-templates/container-schedule/3/README.md create mode 100644 infra-templates/container-schedule/3/README.zh-TW.md create mode 100644 infra-templates/container-schedule/3/docker-compose.yml.tpl create mode 100644 infra-templates/container-schedule/3/rancher-compose.yml create mode 100644 infra-templates/ipsec-overlay/13/README.md create mode 100644 infra-templates/ipsec-overlay/13/README.zh-TW.md create mode 100644 infra-templates/ipsec-overlay/13/docker-compose.yml.tpl create mode 100644 infra-templates/ipsec-overlay/13/rancher-compose.yml create mode 100644 infra-templates/layer-2-flat-network/7/README.md create mode 100644 infra-templates/layer-2-flat-network/7/README.zh-TW.md create mode 100644 infra-templates/layer-2-flat-network/7/docker-compose.yml.tpl create mode 100644 infra-templates/layer-2-flat-network/7/rancher-compose.yml create mode 100644 infra-templates/per-host-subnet-network/5/README.md create mode 100644 infra-templates/per-host-subnet-network/5/README.zh-TW.md create mode 100644 infra-templates/per-host-subnet-network/5/docker-compose.yml.tpl create mode 100644 infra-templates/per-host-subnet-network/5/rancher-compose.yml create mode 100644 infra-templates/vxlan-overlay-network/6/README.md create mode 100644 infra-templates/vxlan-overlay-network/6/README.zh-TW.md create mode 100644 infra-templates/vxlan-overlay-network/6/docker-compose.yml.tpl create mode 100644 infra-templates/vxlan-overlay-network/6/rancher-compose.yml diff --git a/catalog-images.json b/catalog-images.json index 9d4737676..ac74a64c9 100644 --- a/catalog-images.json +++ b/catalog-images.json @@ -1230,6 +1230,52 @@ "source": "component owner verified anonymous manifest/config readback", "workflowRun": "https://github.com/PastureStack/external-dns-sync/actions/runs/39960962858" } + }, + { + "sourceRepository": "https://github.com/PastureStack/container-cron", + "sourcePath": "package/Dockerfile", + "registryPage": "https://github.com/orgs/PastureStack/packages/container/package/container-cron", + "licenseBoundary": "Apache-2.0 source and image; bundled Ubuntu and Go dependencies retain their upstream licenses and notices", + "platforms": [ + "linux/amd64" + ], + "reference": "ghcr.io/pasturestack/container-cron:v0.6.1", + "sourceCommit": "2cce2cc80f2590239d5ef758a21c54a3f1e0f2b9", + "manifestDigest": "sha256:ea2790f2a3e32eb6e3266eb175ee0a69c4a854463c22a74604f69855da5c6829", + "reviewedAt": "2026-10-23", + "vulnerabilityScan": { + "scope": "published runtime image", + "high": 0, + "critical": 0, + "evidence": "https://github.com/PastureStack/container-cron/actions/runs/39960497907" + }, + "publicationVerification": { + "source": "component owner verified anonymous manifest/config readback", + "workflowRun": "https://github.com/PastureStack/container-cron/actions/runs/39960497907" + } + }, + { + "sourceRepository": "https://github.com/PastureStack/ipsec-vxlan-overlay-network", + "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", + "platforms": [ + "linux/amd64" + ], + "reference": "ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39", + "sourceCommit": "db0780394644c70c4756b33301d8b9d75d0149ca", + "manifestDigest": "sha256:72a9fec50190c25ff8b2cdbf954b22a58a93087d64ff15b3d2d9d2ca9526cbfe", + "reviewedAt": "2026-10-23", + "vulnerabilityScan": { + "scope": "published runtime image", + "high": 0, + "critical": 0, + "evidence": "https://github.com/PastureStack/ipsec-vxlan-overlay-network/actions/runs/39963426128" + }, + "publicationVerification": { + "source": "component owner verified anonymous manifest/config readback", + "workflowRun": "https://github.com/PastureStack/ipsec-vxlan-overlay-network/actions/runs/39963426128" + } } ] } diff --git a/infra-templates/container-schedule/3/README.md b/infra-templates/container-schedule/3/README.md new file mode 100644 index 000000000..dcb948da5 --- /dev/null +++ b/infra-templates/container-schedule/3/README.md @@ -0,0 +1,47 @@ + + +# PastureStack Container Schedule v0.6.0 + +This infrastructure service watches Docker container events and runs scheduled +`start`, `stop`, or `restart` actions. A managed workload opts in with these +labels: + +- `cron.schedule`: required six-field Cron expression. +- `cron.action`: optional `start`, `stop`, or `restart`; the default is + `start`. +- `cron.restart_timeout`: optional stop or restart timeout in seconds. + +## Reviewed image + +- Image: `ghcr.io/pasturestack/container-cron:v0.6.0` +- Source: [`PastureStack/container-cron@8645472791ebbc9f78628af716e061139554fb38`](https://github.com/PastureStack/container-cron/tree/8645472791ebbc9f78628af716e061139554fb38) +- Source license: Apache-2.0; Ubuntu and bundled Go dependencies retain their + upstream licenses +- Security gate: Trivy HIGH 0 and CRITICAL 0 for the operating system and Go + binary +- Distribution gate: public GHCR and anonymous version-tag manifest access + passed + +## Security boundary + +The service mounts `/var/run/docker.sock` read-write so it can control +containers. Docker socket access is equivalent to host administrator access. +Deploy this card only as a trusted global infrastructure service. It does not +request privileged mode, publish a host port, or accept a remote Docker +endpoint by default. + +The compatible control plane requires the literal `rancher-compose.yml` +filename and `io.rancher.*` scheduling labels in this template. They are +protocol identifiers, not PastureStack branding. + +## Validation + +The release passed race-enabled unit tests, static analysis, image metadata and +license checks, a current HIGH/CRITICAL vulnerability scan, and an isolated +Docker 29.4 lifecycle test. The test created one stopped workload and one +running workload, then verified that the service started the first and stopped +the second on schedule. All test containers were removed afterward. + +The deployment intentionally uses the neutral container-event mode. It does +not depend on a branded legacy command-line switch or on service-state +translation through Metadata. diff --git a/infra-templates/container-schedule/3/README.zh-TW.md b/infra-templates/container-schedule/3/README.zh-TW.md new file mode 100644 index 000000000..f5ffb943a --- /dev/null +++ b/infra-templates/container-schedule/3/README.zh-TW.md @@ -0,0 +1,42 @@ + + +# PastureStack 容器定時排程 v0.6.0 + +此基礎架構服務會監看 Docker 容器事件,並依排程執行 `start`、 +`stop` 或 `restart`。受管工作負載可使用下列標籤啟用排程: + +- `cron.schedule`:必填,使用六欄式 Cron 表達式。 +- `cron.action`:選填,可設為 `start`、`stop` 或 `restart`; + 預設為 `start`。 +- `cron.restart_timeout`:選填,停止或重新啟動容器的逾時秒數。 + +## 已審核映像 + +- 映像:`ghcr.io/pasturestack/container-cron:v0.6.0` +- 原始碼: + [`PastureStack/container-cron@8645472791ebbc9f78628af716e061139554fb38`](https://github.com/PastureStack/container-cron/tree/8645472791ebbc9f78628af716e061139554fb38) +- 原始碼採 Apache-2.0 授權;Ubuntu 與內含的 Go 相依套件保留各自的 + 上游授權。 +- Trivy 掃描結果為 HIGH 0、CRITICAL 0。 +- 公開 GHCR 與未登入存取版本標籤的驗證已通過。 + +## 安全性界線 + +此服務需要以讀寫方式掛載 `/var/run/docker.sock` 才能控制容器。 +Docker Socket 權限等同主機管理者權限,因此只能將此範本當成受信任 +的全域基礎架構服務部署。此服務預設不要求特權模式、不公開主機連接埠, +也不接受遠端 Docker 端點。 + +相容控制平面仍需要名為 `rancher-compose.yml` 的檔案及 +`io.rancher.*` 排程標籤。這些是相容協定識別名稱,不是目前的產品 +品牌。 + +## 驗證 + +此版本已通過啟用競爭偵測的單元測試、靜態分析、映像中繼資料與授權 +檢查、弱點掃描,以及 Docker 29.4 隔離環境生命週期測試。測試確認 +服務能依排程啟動一個已停止的工作負載,並停止另一個執行中的工作負載; +測試資源已精確移除。 + +部署採用中性的容器事件模式,不依賴舊品牌的命令列參數,也不透過 +中繼資料轉譯服務狀態。 diff --git a/infra-templates/container-schedule/3/docker-compose.yml.tpl b/infra-templates/container-schedule/3/docker-compose.yml.tpl new file mode 100644 index 000000000..9047a82fb --- /dev/null +++ b/infra-templates/container-schedule/3/docker-compose.yml.tpl @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: MIT +version: '2' +services: + container-schedule: + image: ghcr.io/pasturestack/container-cron:v0.6.1 + restart: always + command: container-cron{{- if eq .Values.ENABLE_DEBUG "true" }} --debug{{- end }}{{- if eq .Values.ENABLE_METRICS "true" }} --metrics{{- end }} + volumes: + - /var/run/docker.sock:/var/run/docker.sock + expose: + - '9191' + labels: + io.rancher.scheduler.global: 'true' + io.rancher.container.hostname_override: container_name + logging: + driver: json-file + options: + max-size: 25m + max-file: '2' diff --git a/infra-templates/container-schedule/3/rancher-compose.yml b/infra-templates/container-schedule/3/rancher-compose.yml new file mode 100644 index 000000000..1817aeeb0 --- /dev/null +++ b/infra-templates/container-schedule/3/rancher-compose.yml @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: MIT +.catalog: + name: PastureStack Container Schedule + version: v0.6.1 + description: Run scheduled start, stop, or restart actions from container labels. + minimum_rancher_version: v1.6.15-rc1 + labels: + io.pasturestack.catalog.question.enable_metrics.label.zh-tw: '啟用指標端點' + io.pasturestack.catalog.question.enable_metrics.description.zh-tw: '在容器連接埠 9191 提供 Prometheus 工作執行次數。' + io.pasturestack.catalog.question.enable_debug.label.zh-tw: '啟用除錯日誌' + io.pasturestack.catalog.question.enable_debug.description.zh-tw: '記錄較詳細的事件與排程診斷資訊。' + questions: + - variable: ENABLE_METRICS + label: Enable the metrics endpoint + description: Expose Prometheus job counts on container port 9191. + type: boolean + default: false + required: true + - variable: ENABLE_DEBUG + label: Enable debug logging + description: Write detailed event and scheduling diagnostics. + type: boolean + default: false + required: true + +container-schedule: + scale: 1 + start_on_create: true diff --git a/infra-templates/container-schedule/config.yml b/infra-templates/container-schedule/config.yml index 8b5c31a32..7105273c0 100644 --- a/infra-templates/container-schedule/config.yml +++ b/infra-templates/container-schedule/config.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT name: Container Schedule description: Run scheduled start, stop, or restart actions from container labels. -version: v0.6.0 +version: v0.6.1 category: System maintainer: PastureStack contributors license: MIT template; Apache-2.0 image and bundled dependency licenses apply diff --git a/infra-templates/ipsec-overlay/13/README.md b/infra-templates/ipsec-overlay/13/README.md new file mode 100644 index 000000000..bb64c0c1a --- /dev/null +++ b/infra-templates/ipsec-overlay/13/README.md @@ -0,0 +1,36 @@ + + +# PastureStack IPsec Overlay 0.3.10 + +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.38`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/releases/tag/v0.14.38) was publicly verified on 2026-10-05. Its manifest digest is `sha256:5b29e08dca8a92fc0ecc7f9d0fdae0457b89daa9d02b1c1c3257bc9dd617c3ae`, recorded only as verification evidence in `catalog-images.json`. +- Source: [`c143e9a5f21ba6df2d1c5002340c71777f875c89`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/c143e9a5f21ba6df2d1c5002340c71777f875c89), with a verified commit signature. The annotated Git tag `v0.14.38` is not signed. +- Version `12` updates all four services to the published `v0.14.38` image. It retains version `11`'s namespace, sidekick, XFRM, firewall-selection and CNI-ownership contracts unchanged. Version `11` and its original `v0.14.35` inventory remain available for existing stacks. +- Version `11` explicitly declares `allowSharedSubnetIngress: true` for the fixed `10.42.0.0/16` CNI network. Network Plugin Manager `v0.8.20` uses that contract to restore cross-host workload forwarding without granting traffic outside the configured subnet or managed bridge. Version `10` remains available for existing stacks. +- 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/` 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. Its explicit `allowSharedSubnetIngress` contract is consumed only by Network Plugin Manager. The IPsec router continues to own XFRM and routes without writing host firewall rules. + +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 + +Public readback verified the `v0.14.38` image manifest and config, version and source labels, and its linux/amd64 runtime scan with HIGH, CRITICAL and secrets each zero. This runtime-only result is not a zero-CVE or builder-clean claim. Catalog version `12` is still a candidate: its exact-source Catalog validation and API version lookup remain separate gates. No QA deployment or complete firewall-mode/plugin matrix is claimed. Isolated native nftables, iptables-nft and iptables-legacy checks, managed upgrade, peer restart and rollback must be accepted separately; a successful CNI address allocation alone does not prove the encrypted multi-host lifecycle. diff --git a/infra-templates/ipsec-overlay/13/README.zh-TW.md b/infra-templates/ipsec-overlay/13/README.zh-TW.md new file mode 100644 index 000000000..c68ed3534 --- /dev/null +++ b/infra-templates/ipsec-overlay/13/README.zh-TW.md @@ -0,0 +1,95 @@ + + +# PastureStack IPsec 加密網路 0.3.10 + +此候選基礎架構範本預計在每台符合條件的主機上安裝 IPsec 加密 +網路資料平面。網路持有服務負責受管命名空間;路由器套用主機 XFRM +與路由狀態;連線檢查相關容器提供控制平面健康狀態契約;CNI 相關 +容器則提供網橋與位址管理執行檔。 + +## 候選範本:映像已發布 + +- [映像 `ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.38`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/releases/tag/v0.14.38) + 已於 2026-10-05 完成公開發布讀回。真實 manifest digest 為 + `sha256:5b29e08dca8a92fc0ecc7f9d0fdae0457b89daa9d02b1c1c3257bc9dd617c3ae`, + 僅作為 `catalog-images.json` 中的驗證證據,不加入部署映像引用。 +- [來源 `c143e9a5f21ba6df2d1c5002340c71777f875c89`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/c143e9a5f21ba6df2d1c5002340c71777f875c89) + 的 commit 簽章已驗證;Git tag `v0.14.38` 為 annotated tag,但未簽章。 +- 第 `12` 版將四個服務更新至已發布的 `v0.14.38` 映像,完整保留 + 第 `11` 版的命名空間、相關容器、XFRM、防火牆選擇與 CNI 責任契約。 + 第 `11` 版及其原有 `v0.14.35` inventory 仍供既有堆疊使用。 +- 第 `11` 版為固定的 `10.42.0.0/16` CNI 網路明確設定 + `allowSharedSubnetIngress: true`。網路外掛管理器 `v0.8.20` 依此契約 + 恢復跨主機工作負載轉送,且不放行設定子網路或受管網橋以外的流量。 + 第 `10` 版仍供既有堆疊使用。 +- 第 `10` 版在滾動升級時,若舊版連線檢查容器尚占用 TCP 80, + 新版只對此埠占用情況等待,最多 90 秒;其他監聽錯誤或逾時仍會 + 明確失敗。此處不更動防火牆規則或路由器的 8111 連接埠責任。 + 第 `9` 版仍供既有堆疊使用。 +- 第 `8` 版保留對等主機重試與 8111 連接埠交接。IPsec 模組統一負責 + 缺失 SA 的重建;超過觀察期間且同一對等主機恰有一條已使用的健康 + SA 時,才清除另一條零流量的重複 SA。無法明確判斷的連線不動。 + 第 `7` 版仍供既有堆疊參照,但真機滾動升級後曾留下兩條已建立 SA。 +- 第 `9` 版將隨附 CNI 的主機標籤查詢改為控制平面實際提供的純文字 + `/self/host/labels/` 契約,讓每主機子網路可正確取得網橋與 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` 相容網路。執行環境無法安全套用 +任意子網路,因此範本不提供無效的子網路選項。 +明確的 `allowSharedSubnetIngress` 契約只由網路外掛管理器處理;IPsec +路由器仍只負責 XFRM 與路由,不寫入主機防火牆規則。 + +主機防火牆後端可選 `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.38` 映像的 manifest、config、版本與來源標籤, +以及 linux/amd64 執行映像掃描的 HIGH、CRITICAL 與 secrets 均為零。 +這只代表執行映像的結果,不是零 CVE 或建置映像無風險的宣告。 +第 `12` 版 Catalog 範本仍為候選;精確來源的 Catalog 驗證及 API +版本查詢是分開的驗收關卡,尚未宣告 QA 部署或完整防火牆模式/外掛矩陣通過。 +原生 nftables、iptables-nft 與 iptables-legacy 的隔離檢查、受管升級、 +對等主機重啟及回復須另行驗收。仍須確認暫時離線的主機不拆掉其他 +健康連線、同一對等主機收斂為一條可用 IKE SA、新路由器等待 8111 +埠釋放,且不越界修改網路外掛管理器的防火牆規則。 +單純完成 CNI 位址分配不能代替加密跨主機生命週期驗收。 diff --git a/infra-templates/ipsec-overlay/13/docker-compose.yml.tpl b/infra-templates/ipsec-overlay/13/docker-compose.yml.tpl new file mode 100644 index 000000000..86e37344a --- /dev/null +++ b/infra-templates/ipsec-overlay/13/docker-compose.yml.tpl @@ -0,0 +1,115 @@ +# SPDX-License-Identifier: MIT +version: '2' + +services: + overlay-network: + image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39 + 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.39 + 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.39 + 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.39 + 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 + allowSharedSubnetIngress: true + 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}' diff --git a/infra-templates/ipsec-overlay/13/rancher-compose.yml b/infra-templates/ipsec-overlay/13/rancher-compose.yml new file mode 100644 index 000000000..3a603df60 --- /dev/null +++ b/infra-templates/ipsec-overlay/13/rancher-compose.yml @@ -0,0 +1,97 @@ +# SPDX-License-Identifier: MIT +.catalog: + name: PastureStack IPsec Overlay + version: v0.3.11 + description: Provide an encrypted host-to-host network for managed workloads. + minimum_rancher_version: v1.6.19-rc1 + labels: + io.pasturestack.catalog.question.docker_bridge.label.zh-tw: 'Docker 網橋' + io.pasturestack.catalog.question.docker_bridge.description.zh-tw: '受管工作負載流量使用的主機網橋。' + io.pasturestack.catalog.question.firewall_backend.label.zh-tw: '主機防火牆後端' + io.pasturestack.catalog.question.firewall_backend.description.zh-tw: '依 Docker 現役後端自動選擇;不論 Ubuntu 版本,原生 nftables、iptables-nft 與 iptables-legacy 分開使用。指定不符時安全停止,不會自動切換後端。' + io.pasturestack.catalog.question.mtu.label.zh-tw: '網路 MTU' + io.pasturestack.catalog.question.mtu.description.zh-tw: '請與主機網路 MTU 一致;GCE 常用 1460,一般乙太網路常用 1500。' + io.pasturestack.catalog.question.pasturestack_debug.label.zh-tw: '啟用除錯日誌' + io.pasturestack.catalog.question.pasturestack_debug.description.zh-tw: '記錄較詳細的加密網路元件診斷資訊。' + io.pasturestack.catalog.question.host_ports.label.zh-tw: '啟用主機連接埠' + io.pasturestack.catalog.question.host_ports.description.zh-tw: '允許受管工作負載在主機上公開連接埠。' + io.pasturestack.catalog.question.pasturestack_hairpin_mode.label.zh-tw: '啟用 Hairpin 模式' + io.pasturestack.catalog.question.pasturestack_hairpin_mode.description.zh-tw: 'Hairpin 模式與混雜模式不可同時啟用。' + io.pasturestack.catalog.question.pasturestack_promiscuous_mode.label.zh-tw: '啟用混雜模式' + io.pasturestack.catalog.question.pasturestack_promiscuous_mode.description.zh-tw: '混雜模式與 Hairpin 模式不可同時啟用。' + io.pasturestack.catalog.question.connectivity_check_interval.label.zh-tw: '對等主機檢查間隔' + io.pasturestack.catalog.question.connectivity_check_interval.description.zh-tw: '兩次加密對等主機連線檢查之間的毫秒數。' + io.pasturestack.catalog.question.peer_connection_timeout.label.zh-tw: '對等主機連線逾時' + io.pasturestack.catalog.question.peer_connection_timeout.description.zh-tw: '每次嘗試連線對等主機可使用的毫秒數。' + questions: + - variable: DOCKER_BRIDGE + label: Docker bridge + description: Host bridge used for managed workload traffic. + type: string + default: docker0 + required: true + - variable: FIREWALL_BACKEND + label: Host firewall backend + description: Follow Docker's active firewall backend on any supported Ubuntu version, or explicitly select native nftables, iptables-nft, or iptables-legacy. An explicit mismatch fails safely; legacy is never a fallback. + type: enum + default: auto + required: true + options: + - auto + - nftables + - iptables-nft + - iptables-legacy + - variable: MTU + label: Network MTU + description: Match the host network MTU; common values are 1460 for GCE and 1500 for Ethernet. + type: int + default: 1500 + required: true + - variable: PASTURESTACK_DEBUG + label: Enable debug logs + description: Enable verbose diagnostic logging for the overlay components. + type: boolean + default: 'false' + required: true + - variable: HOST_PORTS + label: Enable host ports + description: Allow managed workloads to publish ports on their hosts. + type: boolean + default: 'true' + required: true + - variable: PASTURESTACK_HAIRPIN_MODE + label: Enable hairpin mode + description: Hairpin mode and promiscuous mode must not both be enabled. + type: boolean + default: 'false' + required: true + - variable: PASTURESTACK_PROMISCUOUS_MODE + label: Enable promiscuous mode + description: Promiscuous mode and hairpin mode must not both be enabled. + type: boolean + default: 'true' + required: true + - variable: CONNECTIVITY_CHECK_INTERVAL + label: Peer check interval + description: Milliseconds between encrypted peer-connectivity checks. + type: int + default: 10000 + required: true + - variable: PEER_CONNECTION_TIMEOUT + label: Peer connection timeout + description: Milliseconds allowed for each peer connection attempt. + type: int + default: 60000 + required: true + +overlay-network: + health_check: + request_line: GET "/connectivity" "HTTP/1.0" + port: 80 + interval: 5000 + initializing_timeout: 60000 + reinitializing_timeout: 60000 + response_timeout: 2000 + healthy_threshold: 2 + unhealthy_threshold: 3 + strategy: none diff --git a/infra-templates/ipsec-overlay/config.yml b/infra-templates/ipsec-overlay/config.yml index e0e98d5f8..8530bc4af 100644 --- a/infra-templates/ipsec-overlay/config.yml +++ b/infra-templates/ipsec-overlay/config.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT name: IPsec Overlay description: Provide an encrypted host-to-host network for managed workloads. -version: v0.3.10 +version: v0.3.11 category: Networking maintainer: PastureStack contributors license: MIT template; Apache-2.0 image and third-party package licenses apply diff --git a/infra-templates/layer-2-flat-network/7/README.md b/infra-templates/layer-2-flat-network/7/README.md new file mode 100644 index 000000000..317628d88 --- /dev/null +++ b/infra-templates/layer-2-flat-network/7/README.md @@ -0,0 +1,31 @@ +# PastureStack Layer 2 Flat Network + +This infrastructure template connects managed workloads directly to a shared +physical Layer 2 subnet. Every participating host must reach the same subnet +and gateway, and the selected workload range must not overlap DHCP, host, or +infrastructure addresses. + +Automatic bridge setup is disabled by default because moving a host's physical +interface into a bridge can interrupt remote access when the interface, subnet, +or gateway is wrong. Prepare the bridge through the operating system first, or +verify out-of-band console access before enabling automatic setup. + +The template uses +`ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.37`, which contains the +reviewed `pasture-bridge` and `flat-cni-ipam` executables. The image source is +[`PastureStack/ipsec-vxlan-overlay-network@20eb898da1b24ed3b8ab2c0ad212d6523adeddeb`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/20eb898da1b24ed3b8ab2c0ad212d6523adeddeb); +the Flat CNI IPAM source is +[`PastureStack/flat-cni-ipam@4676b320a03fec53ae68899fdf18c7e7f7340356`](https://github.com/PastureStack/flat-cni-ipam/tree/4676b320a03fec53ae68899fdf18c7e7f7340356). + +The template files and icon are MIT licensed. The runtime projects are +Apache-2.0; operating-system packages and bundled components retain their own +upstream licenses and notices. + +Version 6 retains version 5's correctly typed `PASTURESTACK_DEBUG` value and +bridge ownership boundary. Flat IPAM now distinguishes an explicit host +address from a network prefix: it keeps the explicit address, or selects the +first usable address only when that address is present on the bridge. If a +multi-address bridge remains ambiguous, allocation fails instead of guessing. +The change does not alter firewall, IPsec, VXLAN, or physical-interface setup. +Verify the real Layer 2 path and rollback before enabling this optional driver +on a host. diff --git a/infra-templates/layer-2-flat-network/7/README.zh-TW.md b/infra-templates/layer-2-flat-network/7/README.zh-TW.md new file mode 100644 index 000000000..648b36c4f --- /dev/null +++ b/infra-templates/layer-2-flat-network/7/README.zh-TW.md @@ -0,0 +1,26 @@ +# PastureStack 第 2 層平面網路 + +此基礎架構範本會透過主機網橋,將受管工作負載直接連接到共用的實體 +第 2 層子網路。每台參與主機都必須能連上相同的子網路與閘道,而且 +選定的工作負載位址範圍不得與 DHCP、主機或基礎架構位址重疊。 + +自動設定網橋預設為停用。若實體介面、子網路或閘道設定錯誤,把主機 +實體介面移入網橋可能會中斷遠端連線。請優先透過作業系統準備網橋; +若要啟用自動設定,請先確認具備頻外主控台存取方式。 + +此範本使用 +`ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.37`, +其中包含經審核的 `pasture-bridge` 與 `flat-cni-ipam` 執行檔。 +映像原始碼位於 +[`PastureStack/ipsec-vxlan-overlay-network@20eb898da1b24ed3b8ab2c0ad212d6523adeddeb`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/20eb898da1b24ed3b8ab2c0ad212d6523adeddeb), +Flat CNI IPAM 原始碼位於 +[`PastureStack/flat-cni-ipam@4676b320a03fec53ae68899fdf18c7e7f7340356`](https://github.com/PastureStack/flat-cni-ipam/tree/4676b320a03fec53ae68899fdf18c7e7f7340356)。 + +範本檔案與圖示採 MIT 授權;執行專案採 Apache-2.0 授權。作業系統 +套件及隨附元件保留各自的上游授權及聲明。 + +第 6 版保留第 5 版的除錯選項型別與網橋權責。Flat IPAM 現在會區分 +明確的主機位址與網路前綴:明確位址會原樣保留;若設定的是網路前綴, +只有當第一個可用位址確實存在於網橋時才會選用。多位址網橋若仍有歧義, +會停止配置而不擅自猜測。此變更不改動防火牆、IPsec、VXLAN 或實體介面 +設定。啟用此選用驅動程式前,仍須驗證真實第 2 層連線及回復方式。 diff --git a/infra-templates/layer-2-flat-network/7/docker-compose.yml.tpl b/infra-templates/layer-2-flat-network/7/docker-compose.yml.tpl new file mode 100644 index 000000000..ece9eb462 --- /dev/null +++ b/infra-templates/layer-2-flat-network/7/docker-compose.yml.tpl @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: MIT +version: '2' + +services: + layer-2-flat-cni: + image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39 + privileged: true + network_mode: host + pid: host +{{- if eq .Values.AUTO_SETUP_LAYER_2_BRIDGE "true" }} + command: + - /bin/bash + - -ceu + - start-flat.sh && exec start-cni-driver.sh +{{- else }} + command: start-cni-driver.sh +{{- end }} + environment: + PASTURESTACK_DEBUG: '${PASTURESTACK_DEBUG}' + PASTURESTACK_METADATA_ADDRESS: '${PASTURESTACK_METADATA_ADDRESS}' + FLAT_IF: '${FLAT_INTERFACE}' + FLAT_BRIDGE: '${LAYER_2_BRIDGE}' + MTU: '${MTU}' + labels: + io.pasturestack.component: layer-2-flat-cni + io.rancher.network.cni.binary: pasture-bridge + io.rancher.container.dns: 'true' + io.rancher.scheduler.global: 'true' + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - rancher-cni-driver:/opt/cni-driver + logging: + driver: json-file + options: + max-size: 25m + max-file: '2' + network_driver: + name: PastureStack Layer 2 Flat Network + default_network: + name: layer-2-flat + host_ports: {{ .Values.HOST_PORTS }} + subnets: + - network_address: ${SUBNET} + start_address: ${START_ADDRESS} + end_address: ${END_ADDRESS} + dns: + - 169.254.169.250 + dns_search: + - pasture.internal + cni_config: + '10-pasturestack-layer-2-flat.conf': + name: pasturestack-layer-2-flat-network + type: pasture-bridge + bridge: ${LAYER_2_BRIDGE} + bridgeSubnet: ${SUBNET} + logToFile: /var/log/pasturestack-cni.log + isDebugLevel: '${PASTURESTACK_DEBUG}' + hostNat: false + mtu: ${MTU} + skipBridgeConfigureIP: true + skipFastPath: true + ipam: + type: flat-cni-ipam + metadataURL: http://169.254.169.250/2015-12-19 + metadataAddress: 169.254.169.250 + logToFile: /var/log/pasturestack-cni.log + isDebugLevel: '${PASTURESTACK_DEBUG}' + routes: + - dst: 0.0.0.0/0 + gw: ${GATEWAY} diff --git a/infra-templates/layer-2-flat-network/7/rancher-compose.yml b/infra-templates/layer-2-flat-network/7/rancher-compose.yml new file mode 100644 index 000000000..ac8c30fda --- /dev/null +++ b/infra-templates/layer-2-flat-network/7/rancher-compose.yml @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: MIT +.catalog: + name: PastureStack Layer 2 Flat Network + version: v0.3.5 + description: Connect managed workloads directly to a shared Layer 2 subnet through a host bridge. + minimum_rancher_version: v1.6.26-rc1 + labels: + io.pasturestack.catalog.question.layer_2_bridge.label.zh-tw: '第 2 層網橋' + io.pasturestack.catalog.question.layer_2_bridge.description.zh-tw: '共用第 2 層網路使用的既有或自動設定主機網橋。' + io.pasturestack.catalog.question.flat_interface.label.zh-tw: '實體網路介面' + io.pasturestack.catalog.question.flat_interface.description.zh-tw: '只有啟用自動網橋設定時,才會把此主機實體介面加入網橋。' + io.pasturestack.catalog.question.auto_setup_layer_2_bridge.label.zh-tw: '自動設定網橋' + io.pasturestack.catalog.question.auto_setup_layer_2_bridge.description.zh-tw: '把實體介面的位址移到第 2 層網橋;啟用前請先確認可使用主控台連線。' + io.pasturestack.catalog.question.subnet.label.zh-tw: '共用子網路' + io.pasturestack.catalog.question.subnet.description.zh-tw: '主機、網橋、閘道與受管工作負載共用的 IPv4 子網路。' + io.pasturestack.catalog.question.start_address.label.zh-tw: '第一個工作負載位址' + io.pasturestack.catalog.question.start_address.description.zh-tw: '控制平面可分配給受管工作負載的第一個 IPv4 位址。' + io.pasturestack.catalog.question.end_address.label.zh-tw: '最後一個工作負載位址' + io.pasturestack.catalog.question.end_address.description.zh-tw: '控制平面可分配給受管工作負載的最後一個 IPv4 位址。' + io.pasturestack.catalog.question.gateway.label.zh-tw: '預設閘道' + io.pasturestack.catalog.question.gateway.description.zh-tw: '共用子網路中受管工作負載使用的 IPv4 閘道。' + io.pasturestack.catalog.question.mtu.label.zh-tw: '網路 MTU' + io.pasturestack.catalog.question.mtu.description.zh-tw: '實體第 2 層網路端對端支援的 MTU。' + io.pasturestack.catalog.question.host_ports.label.zh-tw: '啟用主機連接埠' + io.pasturestack.catalog.question.host_ports.description.zh-tw: '允許受管工作負載在主機上公開連接埠。' + io.pasturestack.catalog.question.pasturestack_metadata_address.label.zh-tw: '中繼資料服務位址' + io.pasturestack.catalog.question.pasturestack_metadata_address.description.zh-tw: '相容中繼資料服務使用的連結本機 IPv4 位址。' + io.pasturestack.catalog.question.pasturestack_debug.label.zh-tw: '啟用除錯日誌' + io.pasturestack.catalog.question.pasturestack_debug.description.zh-tw: '記錄較詳細的網橋設定與 CNI 操作診斷資訊。' + questions: + - variable: LAYER_2_BRIDGE + label: Layer 2 bridge + description: Existing or automatically configured host bridge used by the shared Layer 2 network. + type: string + default: flatbr0 + required: true + - variable: FLAT_INTERFACE + label: Physical interface + description: Physical host interface to attach to the bridge only when automatic bridge setup is enabled. + type: string + default: eth0 + required: true + - variable: AUTO_SETUP_LAYER_2_BRIDGE + label: Configure the bridge automatically + description: Move the physical interface address onto the Layer 2 bridge. Verify console access before enabling this option. + type: boolean + default: 'false' + required: true + - variable: SUBNET + label: Shared subnet + description: IPv4 subnet shared by the hosts, bridge, gateway, and managed workloads. + type: string + default: 192.0.2.0/24 + required: true + - variable: START_ADDRESS + label: First workload address + description: First IPv4 address that the control plane may assign to a managed workload. + type: string + default: 192.0.2.100 + required: true + - variable: END_ADDRESS + label: Last workload address + description: Last IPv4 address that the control plane may assign to a managed workload. + type: string + default: 192.0.2.199 + required: true + - variable: GATEWAY + label: Default gateway + description: IPv4 gateway for managed workloads on the shared subnet. + type: string + default: 192.0.2.1 + required: true + - variable: MTU + label: Network MTU + description: MTU supported end to end by the physical Layer 2 network. + type: int + default: 1500 + required: true + - variable: HOST_PORTS + label: Enable host ports + description: Allow managed workloads to publish ports on their hosts. + type: boolean + default: 'true' + required: true + - variable: PASTURESTACK_METADATA_ADDRESS + label: Metadata address + description: Link-local IPv4 address of the compatible metadata service. + type: string + default: 169.254.169.250 + required: true + - variable: PASTURESTACK_DEBUG + label: Enable debug logs + description: Enable verbose diagnostics for bridge setup and CNI operations. + type: boolean + default: 'false' + required: true diff --git a/infra-templates/layer-2-flat-network/config.yml b/infra-templates/layer-2-flat-network/config.yml index 9c3294aad..1c66a2fd5 100644 --- a/infra-templates/layer-2-flat-network/config.yml +++ b/infra-templates/layer-2-flat-network/config.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT name: Layer 2 Flat Network description: Connect managed workloads directly to a shared Layer 2 subnet through a host bridge. -version: v0.3.4 +version: v0.3.5 category: Networking maintainer: PastureStack contributors license: MIT template; Apache-2.0 image and bundled component licenses apply diff --git a/infra-templates/per-host-subnet-network/5/README.md b/infra-templates/per-host-subnet-network/5/README.md new file mode 100644 index 000000000..c5533bac5 --- /dev/null +++ b/infra-templates/per-host-subnet-network/5/README.md @@ -0,0 +1,37 @@ +# PastureStack Per-Host Subnet Network + +This infrastructure template assigns a different workload subnet to each host +and maintains marked host-gateway routes between those subnets. Before +deployment, add a unique label to every participating host: + +```text +io.pasturestack.network.per-host-subnet.subnet=10.50.1.0/24 +``` + +Use a different, non-overlapping subnet on each host. Optional allocation +bounds use +`io.pasturestack.network.per-host-subnet.range-start` and +`io.pasturestack.network.per-host-subnet.range-end`. The controller accepts +`io.pasturestack.network.per-host-subnet.override-agent-ip` only when metadata +does not advertise the address that other hosts can route through. + +The template uses +`ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.34`. The image source is +[`PastureStack/ipsec-vxlan-overlay-network@db5a506346f521c6947b21a1a60cef6dd546f983`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/db5a506346f521c6947b21a1a60cef6dd546f983); +the bundled controller is from +[`PastureStack/per-host-subnet@babe7d7f2b7f67a18883b9ed99d17483c8854315`](https://github.com/PastureStack/per-host-subnet/tree/babe7d7f2b7f67a18883b9ed99d17483c8854315), +and the bundled IPAM executable is from +[`PastureStack/host-local-cni-ipam@e79e1721f78a9579145cd89d8ad5083ae24633f5`](https://github.com/PastureStack/host-local-cni-ipam/tree/e79e1721f78a9579145cd89d8ad5083ae24633f5). + +The template files and icon are MIT licensed. The runtime projects are +Apache-2.0; operating-system packages and bundled components retain their own +upstream licenses and notices. + +Version 4 preserves `PASTURESTACK_DEBUG` as a string in the generated CNI JSON, +matching the CNI schema when the Catalog answer is a boolean. Version 3 resolves +host-specific bridge and IPAM labels through the control +plane's plain-text `/self/host/labels/` endpoint. The previous version's +JSON assumption prevented managed workload creation on a real host. A subnet +label must be valid and non-overlapping; Network Plugin Manager validates it +before applying host firewall rules. This driver is optional, not a second +Catalog vendor or an automatic replacement for the encrypted IPsec overlay. diff --git a/infra-templates/per-host-subnet-network/5/README.zh-TW.md b/infra-templates/per-host-subnet-network/5/README.zh-TW.md new file mode 100644 index 000000000..86218f1aa --- /dev/null +++ b/infra-templates/per-host-subnet-network/5/README.zh-TW.md @@ -0,0 +1,35 @@ +# PastureStack 每台主機獨立子網路 + +此基礎架構範本會為每台主機分配不同的工作負載子網路,並維護這些 +子網路之間帶有專用標記的主機閘道路由。部署前,請為每台參與主機 +新增唯一標籤: + +```text +io.pasturestack.network.per-host-subnet.subnet=10.50.1.0/24 +``` + +每台主機必須使用互不重疊的子網路。可用 +`io.pasturestack.network.per-host-subnet.range-start` 與 +`io.pasturestack.network.per-host-subnet.range-end` 限制分配範圍。 +只有中繼資料沒有提供其他主機可路由的位址時,控制器才會接受 +`io.pasturestack.network.per-host-subnet.override-agent-ip`。 + +此範本使用 +`ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.34`。 +映像原始碼位於 +[`PastureStack/ipsec-vxlan-overlay-network@db5a506346f521c6947b21a1a60cef6dd546f983`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/db5a506346f521c6947b21a1a60cef6dd546f983), +隨附控制器來自 +[`PastureStack/per-host-subnet@babe7d7f2b7f67a18883b9ed99d17483c8854315`](https://github.com/PastureStack/per-host-subnet/tree/babe7d7f2b7f67a18883b9ed99d17483c8854315), +隨附 IPAM 執行檔來自 +[`PastureStack/host-local-cni-ipam@e79e1721f78a9579145cd89d8ad5083ae24633f5`](https://github.com/PastureStack/host-local-cni-ipam/tree/e79e1721f78a9579145cd89d8ad5083ae24633f5)。 + +範本檔案與圖示採 MIT 授權;執行專案採 Apache-2.0 授權。作業系統 +套件及隨附元件保留各自的上游授權及聲明。 + +第 4 版會把 Catalog 的布林除錯選項明確保留為 CNI JSON 所要求的字串, +避免受管工作負載建立時發生型別解析錯誤。第 3 版透過控制平面實際提供的 +純文字 `/self/host/labels/` +端點解析主機專屬網橋及 IPAM 標籤;舊版將回應誤當 JSON,會使真機 +受管工作負載建立失敗。子網路標籤必須有效且互不重疊,網路外掛管理器 +會在套用主機防火牆規則前驗證。本驅動程式為選用功能,不會另外建立 +商店供應者,也不會自動取代加密的 IPsec 覆疊網路。 diff --git a/infra-templates/per-host-subnet-network/5/docker-compose.yml.tpl b/infra-templates/per-host-subnet-network/5/docker-compose.yml.tpl new file mode 100644 index 000000000..6be66d00a --- /dev/null +++ b/infra-templates/per-host-subnet-network/5/docker-compose.yml.tpl @@ -0,0 +1,78 @@ +# SPDX-License-Identifier: MIT +version: '2' + +services: + per-host-subnet-controller: + image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39 + command: per-host-subnet + privileged: true + network_mode: host + pid: host + environment: + PLATFORM_DEBUG: '${PASTURESTACK_DEBUG}' + PLATFORM_METADATA_URL: http://169.254.169.250/2016-07-29 + PLATFORM_METADATA_STARTUP_TIMEOUT: '${METADATA_STARTUP_TIMEOUT}' + PLATFORM_WATCH_INTERVAL: '${WATCH_INTERVAL}' + PLATFORM_ENABLE_ROUTE_UPDATE: '${ENABLE_ROUTE_UPDATE}' + PLATFORM_ROUTE_UPDATE_PROVIDER: host-gateway + labels: + io.pasturestack.component: per-host-subnet-controller + io.rancher.scheduler.global: 'true' + logging: + driver: json-file + options: + max-size: 25m + max-file: '2' + + per-host-subnet-cni: + image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39 + command: start-cni-driver.sh + privileged: true + network_mode: host + pid: host + environment: + PASTURESTACK_DEBUG: '${PASTURESTACK_DEBUG}' + labels: + io.pasturestack.component: per-host-subnet-cni + io.rancher.network.cni.binary: pasture-bridge + io.rancher.container.dns: 'true' + io.rancher.scheduler.global: 'true' + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - rancher-cni-driver:/opt/cni-driver + logging: + driver: json-file + options: + max-size: 25m + max-file: '2' + network_driver: + name: PastureStack Per-Host Subnet Network + default_network: + name: per-host-subnet + host_ports: {{ .Values.HOST_PORTS }} + dns: + - 169.254.169.250 + dns_search: + - pasture.internal + cni_config: + '10-pasturestack-per-host-subnet.conf': + name: pasturestack-per-host-subnet-network + type: pasture-bridge + bridge: ${BRIDGE} + bridgeSubnet: '__host_label__: io.pasturestack.network.per-host-subnet.subnet' + logToFile: /var/log/pasturestack-cni.log + isDebugLevel: '${PASTURESTACK_DEBUG}' + isDefaultGateway: true + hostNat: {{ .Values.HOST_NAT }} + hairpinMode: {{ .Values.HAIRPIN_MODE }} + promiscMode: {{ .Values.PROMISCUOUS_MODE }} + mtu: ${MTU} + ipam: + type: host-local-cni-ipam + subnet: '__host_label__: io.pasturestack.network.per-host-subnet.subnet' + rangeStart: '__host_label__: io.pasturestack.network.per-host-subnet.range-start' + rangeEnd: '__host_label__: io.pasturestack.network.per-host-subnet.range-end' + dataDir: /opt/cni/state + metadataURL: http://169.254.169.250/2016-07-29 + logToFile: /var/log/pasturestack-cni.log + isDebugLevel: '${PASTURESTACK_DEBUG}' diff --git a/infra-templates/per-host-subnet-network/5/rancher-compose.yml b/infra-templates/per-host-subnet-network/5/rancher-compose.yml new file mode 100644 index 000000000..b453eee53 --- /dev/null +++ b/infra-templates/per-host-subnet-network/5/rancher-compose.yml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: MIT +.catalog: + name: PastureStack Per-Host Subnet Network + version: v0.3.3 + description: Assign a distinct workload subnet to each host and maintain host-gateway routes between hosts. + minimum_rancher_version: v1.6.26-rc1 + labels: + io.pasturestack.catalog.question.bridge.label.zh-tw: '工作負載網橋' + io.pasturestack.catalog.question.bridge.description.zh-tw: '每台主機的受管工作負載子網路使用的主機網橋。' + io.pasturestack.catalog.question.mtu.label.zh-tw: '網路 MTU' + io.pasturestack.catalog.question.mtu.description.zh-tw: '所有參與主機之間端對端支援的 MTU。' + io.pasturestack.catalog.question.enable_route_update.label.zh-tw: '維護主機路由' + io.pasturestack.catalog.question.enable_route_update.description.zh-tw: '維護前往其他主機工作負載子網路且帶有專用標記的主機閘道路由。' + io.pasturestack.catalog.question.host_nat.label.zh-tw: '啟用主機 NAT' + io.pasturestack.catalog.question.host_nat.description.zh-tw: '對離開各主機專用工作負載子網路的流量套用主機 NAT。' + io.pasturestack.catalog.question.host_ports.label.zh-tw: '啟用主機連接埠' + io.pasturestack.catalog.question.host_ports.description.zh-tw: '允許受管工作負載在主機上公開連接埠。' + io.pasturestack.catalog.question.hairpin_mode.label.zh-tw: '啟用 Hairpin 模式' + io.pasturestack.catalog.question.hairpin_mode.description.zh-tw: 'Hairpin 模式與混雜模式不可同時啟用。' + io.pasturestack.catalog.question.promiscuous_mode.label.zh-tw: '啟用混雜模式' + io.pasturestack.catalog.question.promiscuous_mode.description.zh-tw: '混雜模式與 Hairpin 模式不可同時啟用。' + io.pasturestack.catalog.question.metadata_startup_timeout.label.zh-tw: '中繼資料服務啟動逾時' + io.pasturestack.catalog.question.metadata_startup_timeout.description.zh-tw: '控制器結束前,等待中繼資料服務可用的最長時間。' + io.pasturestack.catalog.question.watch_interval.label.zh-tw: '中繼資料監看間隔' + io.pasturestack.catalog.question.watch_interval.description.zh-tw: '協調主機路由時使用的重試及長輪詢間隔。' + io.pasturestack.catalog.question.pasturestack_debug.label.zh-tw: '啟用除錯日誌' + io.pasturestack.catalog.question.pasturestack_debug.description.zh-tw: '記錄較詳細的子網路、路由與 CNI 操作診斷資訊。' + questions: + - variable: BRIDGE + label: Workload bridge + description: Host bridge used for each host's managed workload subnet. + type: string + default: docker0 + required: true + - variable: MTU + label: Network MTU + description: MTU supported end to end between all participating hosts. + type: int + default: 1500 + required: true + - variable: ENABLE_ROUTE_UPDATE + label: Maintain host routes + description: Maintain marked host-gateway routes for the other hosts' workload subnets. + type: boolean + default: 'true' + required: true + - variable: HOST_NAT + label: Enable host NAT + description: Apply host NAT to traffic leaving each host-specific workload subnet. + type: boolean + default: 'true' + required: true + - variable: HOST_PORTS + label: Enable host ports + description: Allow managed workloads to publish ports on their hosts. + type: boolean + default: 'true' + required: true + - variable: HAIRPIN_MODE + label: Enable hairpin mode + description: Hairpin mode and promiscuous mode must not both be enabled. + type: boolean + default: 'false' + required: true + - variable: PROMISCUOUS_MODE + label: Enable promiscuous mode + description: Promiscuous mode and hairpin mode must not both be enabled. + type: boolean + default: 'true' + required: true + - variable: METADATA_STARTUP_TIMEOUT + label: Metadata startup timeout + description: Maximum time to wait for the metadata service before the controller exits. + type: string + default: 2m + required: true + - variable: WATCH_INTERVAL + label: Metadata watch interval + description: Retry and long-poll interval used while reconciling host routes. + type: string + default: 5s + required: true + - variable: PASTURESTACK_DEBUG + label: Enable debug logs + description: Enable verbose diagnostics for subnet, route, and CNI operations. + type: boolean + default: 'false' + required: true diff --git a/infra-templates/per-host-subnet-network/config.yml b/infra-templates/per-host-subnet-network/config.yml index 8ebfb9b4d..8d3bd85a2 100644 --- a/infra-templates/per-host-subnet-network/config.yml +++ b/infra-templates/per-host-subnet-network/config.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT name: Per-Host Subnet Network description: Assign a distinct workload subnet to each host and maintain host-gateway routes between hosts. -version: v0.3.2 +version: v0.3.3 category: Networking maintainer: PastureStack contributors license: MIT template; Apache-2.0 image and bundled component licenses apply diff --git a/infra-templates/vxlan-overlay-network/6/README.md b/infra-templates/vxlan-overlay-network/6/README.md new file mode 100644 index 000000000..a24853b2a --- /dev/null +++ b/infra-templates/vxlan-overlay-network/6/README.md @@ -0,0 +1,44 @@ + + +# PastureStack VXLAN Overlay Network 0.3.3 + +This optional infrastructure template installs an unencrypted VXLAN data +plane across managed hosts. It publishes UDP port `4789`, runs one router +sidecar per network holder, and installs the reviewed CNI executables on each +eligible host. + +## Reviewed image + +- Image: `ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.34` +- Template version `5` explicitly declares `allowSharedSubnetIngress: true` for the fixed `10.42.0.0/16` CNI network. Network Plugin Manager `v0.8.20` uses this bounded contract for cross-host workload forwarding; version `4` remains available for existing stacks. +- Source: [`PastureStack/ipsec-vxlan-overlay-network@db5a506346f521c6947b21a1a60cef6dd546f983`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/db5a506346f521c6947b21a1a60cef6dd546f983) +- Source license: Apache-2.0; Ubuntu, CNI, Weave, and bundled dependencies retain their upstream licenses and notices +- Security gate: Trivy HIGH 0, CRITICAL 0, image secrets 0, and personal-marker scan passed +- Runtime gate: the earlier version passed isolated two-node VXLAN forwarding; repeat the managed lifecycle gate for this new image before treating it as production-ready + +## Security and network boundary + +VXLAN encapsulates traffic but does not encrypt or authenticate it. Use this +driver only on a trusted host network. Every participating host must allow +inbound and outbound UDP port `4789`. Select the IPsec template when encrypted +host-to-host traffic is required. + +The router receives `NET_ADMIN` in the network-holder namespace. The CNI +sidecar is privileged, joins the host network and PID namespaces, and accesses +the Docker socket so it can install and operate the compatibility CNI path. +These permissions must not be copied to ordinary workloads. + +The managed network is `10.42.0.0/16`. This release intentionally does not +expose a subnet selector because the reviewed startup path does not safely +honor arbitrary subnets. Network Plugin Manager alone consumes the explicit +shared-subnet ingress contract and owns the corresponding host forwarding +rule; the VXLAN router remains confined to its data-plane namespace. + +## Compatibility boundary + +The literal `rancher-compose.yml` filename, `minimum_rancher_version` key, +required `io.rancher.*` orchestration labels, and `rancher-cni-driver` shared +volume are consumed by the compatible control plane. They are protocol +identifiers, not PastureStack branding. User-facing names, image coordinates, +environment variables, CNI names, log paths, and the `pasture.internal` search +suffix use current PastureStack identifiers. diff --git a/infra-templates/vxlan-overlay-network/6/README.zh-TW.md b/infra-templates/vxlan-overlay-network/6/README.zh-TW.md new file mode 100644 index 000000000..d836ffc2f --- /dev/null +++ b/infra-templates/vxlan-overlay-network/6/README.zh-TW.md @@ -0,0 +1,44 @@ + + +# PastureStack VXLAN 覆疊網路 0.3.3 + +此選用基礎架構範本會在受管主機間安裝未加密的 VXLAN 資料平面。 +範本會公開 UDP `4789`、為每個網路持有服務執行一個路由相關容器, +並在每台符合條件的主機上安裝經審核的 CNI 執行檔。 + +## 已審核映像 + +- 映像:`ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.34` +- 第 `5` 版為固定的 `10.42.0.0/16` CNI 網路明確設定 + `allowSharedSubnetIngress: true`。網路外掛管理器 `v0.8.20` 依此有限 + 契約處理跨主機工作負載轉送;第 `4` 版仍供既有堆疊使用。 +- 原始碼: + [`PastureStack/ipsec-vxlan-overlay-network@db5a506346f521c6947b21a1a60cef6dd546f983`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/db5a506346f521c6947b21a1a60cef6dd546f983) +- 原始碼採 Apache-2.0 授權;Ubuntu、CNI、Weave 及隨附相依套件 + 保留各自的上游授權及聲明。 +- Trivy 結果為 HIGH 0、CRITICAL 0,映像機密資料與個人識別標記 + 掃描均已通過。 +- 舊版已通過隔離雙節點 VXLAN 轉送;此新版映像仍須重新完成受管生命週期驗收,才能宣稱適合正式環境。 + +## 安全性與網路界線 + +VXLAN 只封裝流量,不提供加密或身分驗證。此驅動程式只能用於受信任 +的主機網路,每台參與主機都必須允許 UDP `4789` 的輸入及輸出流量。 +需要主機間加密時,請改用 IPsec 加密網路範本。 + +路由器在網路持有服務的命名空間中使用 `NET_ADMIN`。CNI 相關容器 +使用特權模式、加入主機網路與 PID 命名空間,並存取 Docker Socket +以安裝及操作相容 CNI 路徑。這些權限不得套用到一般工作負載。 + +受管網路為 `10.42.0.0/16`。經審核的啟動流程無法安全套用任意 +子網路,因此此版本不提供無效的子網路選項。只有網路外掛管理器會 +處理明確的共用子網路輸入契約及相對應的主機轉送規則;VXLAN 路由器 +仍只在自己的資料平面命名空間內運作。 + +## 相容性界線 + +`rancher-compose.yml`、`minimum_rancher_version`、必要的 +`io.rancher.*` 編排標籤及 `rancher-cni-driver` 共用磁碟區是相容 +控制平面使用的協定識別名稱,不是目前的產品品牌。使用者可見名稱、 +映像位置、環境變數、CNI 名稱、日誌路徑及 `pasture.internal` +搜尋後綴均採 PastureStack 名稱。 diff --git a/infra-templates/vxlan-overlay-network/6/docker-compose.yml.tpl b/infra-templates/vxlan-overlay-network/6/docker-compose.yml.tpl new file mode 100644 index 000000000..143d3cec1 --- /dev/null +++ b/infra-templates/vxlan-overlay-network/6/docker-compose.yml.tpl @@ -0,0 +1,97 @@ +# SPDX-License-Identifier: MIT +version: '2' + +services: + vxlan-network: + image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39 + command: + - /bin/bash + - -c + - 'mkfifo /tmp/overlay-log; exec cat /tmp/overlay-log' + network_mode: vxlan + ports: + - 4789:4789/udp + labels: + io.pasturestack.component: vxlan-overlay + io.rancher.sidekicks: vxlan-router + io.rancher.scheduler.global: 'true' + io.rancher.cni.link_mtu_overhead: '0' + io.rancher.internal.service.vxlan: 'true' + io.rancher.service.selector.link: io.rancher.internal.service.vxlan=true + io.rancher.network.macsync: 'true' + io.rancher.network.arpsync: 'true' + logging: + driver: json-file + options: + max-size: 25m + max-file: '2' + + vxlan-router: + image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39 + command: start-vxlan.sh + cap_add: + - NET_ADMIN + network_mode: container:vxlan-network + environment: + PASTURESTACK_DEBUG: '${PASTURESTACK_DEBUG}' + 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' + + cni-driver: + image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39 + command: start-cni-driver.sh + privileged: true + network_mode: host + pid: host + environment: + PASTURESTACK_DEBUG: '${PASTURESTACK_DEBUG}' + labels: + io.pasturestack.component: vxlan-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 VXLAN Overlay Network + default_network: + name: vxlan + 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-vxlan.conf': + name: pasturestack-cni-network + type: pasture-bridge + bridge: $DOCKER_BRIDGE + bridgeSubnet: 10.42.0.0/16 + allowSharedSubnetIngress: true + 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: 50 + ipam: + type: metadata-cni-ipam + subnetPrefixSize: /16 + logToFile: /var/log/pasturestack-cni.log + isDebugLevel: '${PASTURESTACK_DEBUG}' diff --git a/infra-templates/vxlan-overlay-network/6/rancher-compose.yml b/infra-templates/vxlan-overlay-network/6/rancher-compose.yml new file mode 100644 index 000000000..0f60ad5f5 --- /dev/null +++ b/infra-templates/vxlan-overlay-network/6/rancher-compose.yml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: MIT +.catalog: + name: PastureStack VXLAN Overlay Network + version: v0.3.4 + description: Provide an unencrypted UDP VXLAN network across managed hosts. + minimum_rancher_version: v1.6.11-rc1 + labels: + io.pasturestack.catalog.question.docker_bridge.label.zh-tw: 'Docker 網橋' + io.pasturestack.catalog.question.docker_bridge.description.zh-tw: '受管工作負載流量使用的主機網橋。' + io.pasturestack.catalog.question.mtu.label.zh-tw: '網路 MTU' + io.pasturestack.catalog.question.mtu.description.zh-tw: '請與主機網路 MTU 一致;GCE 常用 1460,一般乙太網路常用 1500。' + io.pasturestack.catalog.question.pasturestack_debug.label.zh-tw: '啟用除錯日誌' + io.pasturestack.catalog.question.pasturestack_debug.description.zh-tw: '記錄較詳細的 VXLAN 元件診斷資訊。' + io.pasturestack.catalog.question.host_ports.label.zh-tw: '啟用主機連接埠' + io.pasturestack.catalog.question.host_ports.description.zh-tw: '允許受管工作負載在主機上公開連接埠。' + io.pasturestack.catalog.question.pasturestack_hairpin_mode.label.zh-tw: '啟用 Hairpin 模式' + io.pasturestack.catalog.question.pasturestack_hairpin_mode.description.zh-tw: 'Hairpin 模式與混雜模式不可同時啟用。' + io.pasturestack.catalog.question.pasturestack_promiscuous_mode.label.zh-tw: '啟用混雜模式' + io.pasturestack.catalog.question.pasturestack_promiscuous_mode.description.zh-tw: '混雜模式與 Hairpin 模式不可同時啟用。' + questions: + - variable: DOCKER_BRIDGE + label: Docker bridge + description: Host bridge used for managed workload traffic. + type: string + default: docker0 + required: true + - variable: MTU + label: Network MTU + description: Match the host network MTU; common values are 1460 for GCE and 1500 for Ethernet. + type: int + default: 1500 + required: true + - variable: PASTURESTACK_DEBUG + label: Enable debug logs + description: Enable verbose diagnostic logging for the VXLAN components. + type: boolean + default: 'false' + required: true + - variable: HOST_PORTS + label: Enable host ports + description: Allow managed workloads to publish ports on their hosts. + type: boolean + default: 'true' + required: true + - variable: PASTURESTACK_HAIRPIN_MODE + label: Enable hairpin mode + description: Hairpin mode and promiscuous mode must not both be enabled. + type: boolean + default: 'false' + required: true + - variable: PASTURESTACK_PROMISCUOUS_MODE + label: Enable promiscuous mode + description: Promiscuous mode and hairpin mode must not both be enabled. + type: boolean + default: 'true' + required: true diff --git a/infra-templates/vxlan-overlay-network/config.yml b/infra-templates/vxlan-overlay-network/config.yml index 3d6e96fd2..29f9253ef 100644 --- a/infra-templates/vxlan-overlay-network/config.yml +++ b/infra-templates/vxlan-overlay-network/config.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT name: VXLAN Overlay Network description: Provide an unencrypted UDP VXLAN network across managed hosts. -version: v0.3.3 +version: v0.3.4 category: Networking maintainer: PastureStack contributors license: MIT template; Apache-2.0 image and third-party package licenses apply diff --git a/integration/core/test_catalog.py b/integration/core/test_catalog.py index c127587ed..97104e213 100644 --- a/integration/core/test_catalog.py +++ b/integration/core/test_catalog.py @@ -183,10 +183,10 @@ def test_catalog_list(): assert by_folder[('infra', 'container-schedule')][ 'name'] == 'Container Schedule' assert by_folder[('infra', 'container-schedule')][ - 'defaultVersion'] == 'v0.6.0' + 'defaultVersion'] == 'v0.6.1' assert by_folder[('infra', 'container-schedule')][ 'links']['defaultVersion'].endswith( - ':2') + ':3') assert by_folder[('infra', 'ecr-credential-sync')][ 'name'] == 'Amazon ECR Credential Sync' assert by_folder[('infra', 'ecr-credential-sync')][ @@ -204,17 +204,17 @@ def test_catalog_list(): assert by_folder[('infra', 'ipsec-overlay')]['name'] == ( 'IPsec Overlay') assert by_folder[('infra', 'ipsec-overlay')][ - 'defaultVersion'] == 'v0.3.10' + 'defaultVersion'] == 'v0.3.11' assert by_folder[('infra', 'ipsec-overlay')][ 'links']['defaultVersion'].endswith( - ':12') + ':13') assert by_folder[('infra', 'layer-2-flat-network')]['name'] == ( 'Layer 2 Flat Network') assert by_folder[('infra', 'layer-2-flat-network')][ - 'defaultVersion'] == 'v0.3.4' + 'defaultVersion'] == 'v0.3.5' assert by_folder[('infra', 'layer-2-flat-network')][ 'links']['defaultVersion'].endswith( - ':6') + ':7') assert by_folder[('infra', 'network-diagnostics')]['name'] == ( 'Network Diagnostics') assert by_folder[('infra', 'network-diagnostics')][ @@ -260,9 +260,9 @@ def test_catalog_list(): assert by_folder[('infra', 'per-host-subnet-network')]['name'] == ( 'Per-Host Subnet Network') assert by_folder[('infra', 'per-host-subnet-network')][ - 'defaultVersion'] == 'v0.3.2' + 'defaultVersion'] == 'v0.3.3' assert by_folder[('infra', 'per-host-subnet-network')][ - 'links']['defaultVersion'].endswith(':4') + 'links']['defaultVersion'].endswith(':5') assert by_folder[('infra', 'resource-scheduler')][ 'name'] == 'Resource Scheduler' assert by_folder[('infra', 'resource-scheduler')][ @@ -287,10 +287,10 @@ def test_catalog_list(): assert by_folder[('infra', 'vxlan-overlay-network')]['name'] == ( 'VXLAN Overlay Network') assert by_folder[('infra', 'vxlan-overlay-network')][ - 'defaultVersion'] == 'v0.3.3' + 'defaultVersion'] == 'v0.3.4' assert by_folder[('infra', 'vxlan-overlay-network')][ 'links']['defaultVersion'].endswith( - ':5') + ':6') assert by_folder[('infra', 'windows-container-networking')][ 'name'] == 'Windows Container Networking' assert by_folder[('infra', 'windows-container-networking')][ @@ -499,7 +499,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): container_schedule_platform = container_schedule_files[ 'rancher-compose.yml'] container_schedule_image = ( - 'ghcr.io/pasturestack/container-cron:v0.6.0') + 'ghcr.io/pasturestack/container-cron:v0.6.1') assert container_schedule_docker.count( 'image: {}'.format(container_schedule_image)) == 1 assert '\n container-schedule:\n' in container_schedule_docker @@ -565,7 +565,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): overlay_docker = overlay_files['docker-compose.yml.tpl'] overlay_platform = overlay_files['rancher-compose.yml'] overlay_image = ( - 'ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.38') + 'ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39') assert overlay_docker.count('image: {}'.format(overlay_image)) == 4 assert overlay_docker.count( "PASTURESTACK_FIREWALL_BACKEND: '${FIREWALL_BACKEND}'") == 1 @@ -607,7 +607,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): vxlan_docker = vxlan_files['docker-compose.yml.tpl'] vxlan_platform = vxlan_files['rancher-compose.yml'] alternative_network_image = ( - 'ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.34') + 'ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39') assert vxlan_docker.count( 'image: {}'.format(alternative_network_image)) == 3 assert '\n vxlan-network:\n' in vxlan_docker @@ -632,7 +632,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): layer_2_docker = layer_2_files['docker-compose.yml.tpl'] layer_2_platform = layer_2_files['rancher-compose.yml'] flat_network_image = ( - 'ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.37') + 'ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39') assert layer_2_docker.count( 'image: {}'.format(flat_network_image)) == 1 assert '\n layer-2-flat-cni:\n' in layer_2_docker @@ -1148,6 +1148,23 @@ def test_catalog_compose_shapes_are_runtime_compatible(): ), ], ), + ( + 'network-services', '10', '11', + 'v0.3.8', 'v0.3.9', [ + ( + 'network-plugin-manager:v0.8.22', + 'network-plugin-manager:v0.8.23', + ), + ( + 'metadata-service:v0.9.11', + 'metadata-service:v0.10.5', + ), + ( + 'internal-dns:v0.17.11', + 'internal-dns:v0.17.13', + ), + ], + ), ( 'network-policy-manager', '3', '4', 'v0.3.3', 'v0.3.4', [ @@ -1176,19 +1193,47 @@ def test_catalog_compose_shapes_are_runtime_compatible(): ], ), ( - 'network-services', '10', '11', - 'v0.3.8', 'v0.3.9', [ + 'container-schedule', '2', '3', + 'v0.6.0', 'v0.6.1', [ ( - 'network-plugin-manager:v0.8.22', - 'network-plugin-manager:v0.8.23', + 'container-cron:v0.6.0', + 'container-cron:v0.6.1', ), + ], + ), + ( + 'ipsec-overlay', '12', '13', + 'v0.3.10', 'v0.3.11', [ ( - 'metadata-service:v0.9.11', - 'metadata-service:v0.10.5', + 'ipsec-vxlan-overlay-network:v0.14.38', + 'ipsec-vxlan-overlay-network:v0.14.39', ), + ], + ), + ( + 'layer-2-flat-network', '6', '7', + 'v0.3.4', 'v0.3.5', [ ( - 'internal-dns:v0.17.11', - 'internal-dns:v0.17.13', + 'ipsec-vxlan-overlay-network:v0.14.37', + 'ipsec-vxlan-overlay-network:v0.14.39', + ), + ], + ), + ( + 'per-host-subnet-network', '4', '5', + 'v0.3.2', 'v0.3.3', [ + ( + 'ipsec-vxlan-overlay-network:v0.14.34', + 'ipsec-vxlan-overlay-network:v0.14.39', + ), + ], + ), + ( + 'vxlan-overlay-network', '5', '6', + 'v0.3.3', 'v0.3.4', [ + ( + 'ipsec-vxlan-overlay-network:v0.14.34', + 'ipsec-vxlan-overlay-network:v0.14.39', ), ], ), diff --git a/scripts/audit_deployable_images.py b/scripts/audit_deployable_images.py index 7c5c4303d..d5d446c9b 100644 --- a/scripts/audit_deployable_images.py +++ b/scripts/audit_deployable_images.py @@ -51,21 +51,22 @@ "配置文件", ) RETAINED_VERSION_LAYOUTS = { + "container-schedule": ("2", "3"), "ecr-credential-sync": ("2", "3"), "healthcheck": ("0", "1", "2"), - "ipsec-overlay": ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"), - "layer-2-flat-network": ("2", "3", "4", "5", "6"), + "ipsec-overlay": ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13"), + "layer-2-flat-network": ("2", "3", "4", "5", "6", "7"), "network-diagnostics": ("1", "2", "3"), "network-policy-manager": ("1", "2", "3", "4"), "network-services": ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"), "nfs-storage": ("1", "2"), - "per-host-subnet-network": ("2", "3", "4"), + "per-host-subnet-network": ("2", "3", "4", "5"), "route53-dns-sync": ("2", "3"), "resource-scheduler": ("1", "2", "3", "4", "5"), "secret-volume-driver": ("1", "2", "3"), "system-image-preloader": ("2", "3"), "vault-volume-driver": ("3", "4"), - "vxlan-overlay-network": ("2", "3", "4", "5"), + "vxlan-overlay-network": ("2", "3", "4", "5", "6"), "windows-container-networking": ("2", "3"), } RETAINED_VERSION_HASHES = { From f067d4a39363118705a8b0151b82185886368f86 Mon Sep 17 00:00:00 2001 From: chen21019 <19357113+chen21019@users.noreply.github.com> Date: Fri, 23 Oct 2026 22:05:47 +0800 Subject: [PATCH 06/10] Add verified storage and scheduler security revisions --- README.md | 8 +- catalog-images.json | 112 ++++++++++++++++++ catalog-provenance.json | 40 +++++-- .../amazon-ebs-storage/3/README.md | 29 +++++ .../amazon-ebs-storage/3/README.zh-TW.md | 28 +++++ .../amazon-ebs-storage/3/docker-compose.yml | 29 +++++ .../amazon-ebs-storage/3/rancher-compose.yml | 64 ++++++++++ infra-templates/amazon-ebs-storage/config.yml | 2 +- .../amazon-efs-storage/3/README.md | 30 +++++ .../amazon-efs-storage/3/README.zh-TW.md | 30 +++++ .../amazon-efs-storage/3/docker-compose.yml | 31 +++++ .../amazon-efs-storage/3/rancher-compose.yml | 80 +++++++++++++ infra-templates/amazon-efs-storage/config.yml | 2 +- infra-templates/nfs-storage/3/README.md | 46 +++++++ infra-templates/nfs-storage/3/README.zh-TW.md | 44 +++++++ .../nfs-storage/3/docker-compose.yml | 28 +++++ .../nfs-storage/3/rancher-compose.yml | 66 +++++++++++ infra-templates/nfs-storage/config.yml | 2 +- .../resource-scheduler/6/README.md | 24 ++++ .../resource-scheduler/6/README.zh-TW.md | 20 ++++ .../resource-scheduler/6/docker-compose.yml | 16 +++ .../resource-scheduler/6/rancher-compose.yml | 75 ++++++++++++ infra-templates/resource-scheduler/config.yml | 2 +- integration/core/test_catalog.py | 85 +++++++++++-- scripts/audit_deployable_images.py | 6 +- 25 files changed, 867 insertions(+), 32 deletions(-) create mode 100644 infra-templates/amazon-ebs-storage/3/README.md create mode 100644 infra-templates/amazon-ebs-storage/3/README.zh-TW.md create mode 100644 infra-templates/amazon-ebs-storage/3/docker-compose.yml create mode 100644 infra-templates/amazon-ebs-storage/3/rancher-compose.yml create mode 100644 infra-templates/amazon-efs-storage/3/README.md create mode 100644 infra-templates/amazon-efs-storage/3/README.zh-TW.md create mode 100644 infra-templates/amazon-efs-storage/3/docker-compose.yml create mode 100644 infra-templates/amazon-efs-storage/3/rancher-compose.yml create mode 100644 infra-templates/nfs-storage/3/README.md create mode 100644 infra-templates/nfs-storage/3/README.zh-TW.md create mode 100644 infra-templates/nfs-storage/3/docker-compose.yml create mode 100644 infra-templates/nfs-storage/3/rancher-compose.yml create mode 100644 infra-templates/resource-scheduler/6/README.md create mode 100644 infra-templates/resource-scheduler/6/README.zh-TW.md create mode 100644 infra-templates/resource-scheduler/6/docker-compose.yml create mode 100644 infra-templates/resource-scheduler/6/rancher-compose.yml diff --git a/README.md b/README.md index 8ac50d937..3eac935fe 100644 --- a/README.md +++ b/README.md @@ -194,12 +194,12 @@ GitHub CodeQL independently scans the Actions and Python sources. A Server release pins the Catalog only after those gates pass; none of these checks is a production-readiness claim. -## Resource Scheduler 0.8.19 +## Resource Scheduler 0.8.20 -Catalog version `5` selects the published Resource Scheduler `v0.8.19`. +Catalog version `6` selects the published Resource Scheduler `v0.8.20`. It changes only the image and visible version; questions, credentials, -commands, scheduling labels, and port-80 liveness checks retain version `4`'s -contract. Versions `1` through `4` remain unchanged for installed stacks. +commands, scheduling labels, and port-80 liveness checks retain version `5`'s +contract. Versions `1` through `5` remain unchanged for installed stacks. The official release's all-severity runtime scan has 0 High/Critical, 0 vendor-fixed findings, and 0 secrets; 4 Low and 47 Medium vendor-unfixed findings remain `under_investigation`, not resolved. The published manifest, diff --git a/catalog-images.json b/catalog-images.json index ac74a64c9..d886e9ff6 100644 --- a/catalog-images.json +++ b/catalog-images.json @@ -1276,6 +1276,118 @@ "source": "component owner verified anonymous manifest/config readback", "workflowRun": "https://github.com/PastureStack/ipsec-vxlan-overlay-network/actions/runs/39963426128" } + }, + { + "sourceRepository": "https://github.com/PastureStack/storage-plugins", + "sourcePath": "runtime/nfs/image/nfs/Dockerfile", + "registryPage": "https://github.com/orgs/PastureStack/packages/container/package/nfs-storage-driver", + "licenseBoundary": "Apache-2.0 source and image; bundled Ubuntu, NFS client, and other packages retain their upstream licenses and notices", + "platforms": [ + "linux/amd64" + ], + "reference": "ghcr.io/pasturestack/nfs-storage-driver:v0.11.1", + "sourceCommit": "a1ea8a0b483c9f8755cd23a4040cac06eafbb474", + "manifestDigest": "sha256:5b2a9f7d5a65c824ef00c134553b6fb8cb440b5da0cd91c837a0c1844590ec13", + "reviewedAt": "2026-10-23", + "vulnerabilityScan": { + "scope": "published runtime image", + "high": 0, + "critical": 0, + "evidence": "https://github.com/PastureStack/storage-plugins/actions/runs/39964036727" + }, + "publicationVerification": { + "source": "component owner verified anonymous manifest/config readback", + "workflowRun": "https://github.com/PastureStack/storage-plugins/actions/runs/39964036727" + } + }, + { + "sourceRepository": "https://github.com/PastureStack/storage-plugins", + "sourcePath": "runtime/nfs/image/ebs/Dockerfile", + "registryPage": "https://github.com/orgs/PastureStack/packages/container/package/ebs-storage-driver", + "licenseBoundary": "Apache-2.0 source and image; bundled Ubuntu, AWS CLI, filesystem tools, and other packages retain their upstream licenses and notices", + "platforms": [ + "linux/amd64" + ], + "reference": "ghcr.io/pasturestack/ebs-storage-driver:v0.11.1", + "sourceCommit": "a1ea8a0b483c9f8755cd23a4040cac06eafbb474", + "manifestDigest": "sha256:f9b804a4fa3b6e54ce8f18b4becf526b5d48e0117aa2a8e0c690573f57c369ad", + "reviewedAt": "2026-10-23", + "vulnerabilityScan": { + "scope": "published runtime image", + "high": 0, + "critical": 0, + "evidence": "https://github.com/PastureStack/storage-plugins/actions/runs/39964036727" + }, + "publicationVerification": { + "source": "component owner verified anonymous manifest/config readback", + "workflowRun": "https://github.com/PastureStack/storage-plugins/actions/runs/39964036727" + } + }, + { + "sourceRepository": "https://github.com/PastureStack/storage-plugins", + "sourcePath": "runtime/nfs/image/efs/Dockerfile", + "registryPage": "https://github.com/orgs/PastureStack/packages/container/package/efs-storage-driver", + "licenseBoundary": "Apache-2.0 source and image; bundled Ubuntu, AWS CLI, NFS client, and other packages retain their upstream licenses and notices", + "platforms": [ + "linux/amd64" + ], + "reference": "ghcr.io/pasturestack/efs-storage-driver:v0.11.1", + "sourceCommit": "a1ea8a0b483c9f8755cd23a4040cac06eafbb474", + "manifestDigest": "sha256:acd786fa4052b3469242c3071320e72fb8a2cb1b863e51074585c04affb72747", + "reviewedAt": "2026-10-23", + "vulnerabilityScan": { + "scope": "published runtime image", + "high": 0, + "critical": 0, + "evidence": "https://github.com/PastureStack/storage-plugins/actions/runs/39964036727" + }, + "publicationVerification": { + "source": "component owner verified anonymous manifest/config readback", + "workflowRun": "https://github.com/PastureStack/storage-plugins/actions/runs/39964036727" + } + }, + { + "sourceRepository": "https://github.com/PastureStack/resource-scheduler", + "sourcePath": "package/Dockerfile", + "registryPage": "https://github.com/orgs/PastureStack/packages/container/package/resource-scheduler", + "licenseBoundary": "Apache-2.0 source and image; bundled Ubuntu and other packages retain their upstream licenses and notices", + "platforms": [ + "linux/amd64" + ], + "reference": "ghcr.io/pasturestack/resource-scheduler:v0.8.20", + "sourceCommit": "35d3a67c62df4b22d7167da3d73dd9dbc4905e66", + "manifestDigest": "sha256:e5a389273344585fca5c4513060e5289b30ca13046d8ec286b8563952f1325d4", + "reviewedAt": "2026-10-23", + "vulnerabilityScan": { + "scope": "published runtime image", + "high": 0, + "critical": 0, + "low": 4, + "medium": 47, + "secrets": 0, + "fixedAvailable": 0, + "actionable": 0, + "vendorUnfixedLowMedium": 51, + "disposition": "under_investigation", + "evidence": "https://github.com/PastureStack/resource-scheduler/actions/runs/39961862641", + "reportSha256": "c37fb24919c5984fec1024e43a5845f1edb59f272e4f072bf55c85c1084fb175" + }, + "publicationVerification": { + "source": "component owner verified anonymous manifest/config readback", + "workflowRun": "https://github.com/PastureStack/resource-scheduler/actions/runs/39961862641" + }, + "sbom": { + "format": "CycloneDX", + "url": "https://github.com/PastureStack/resource-scheduler/releases/download/v0.8.20/resource-scheduler-0.8.20-image.cdx.json", + "sha256": "56de083886f393483d988c210d307d71a0b9252b5d25a36095b2161bbab15e91", + "provenance": { + "verified": true, + "predicateType": "https://slsa.dev/provenance/v1", + "signerWorkflow": "PastureStack/resource-scheduler/.github/workflows/release.yml", + "sourceRef": "refs/tags/v0.8.20", + "sourceCommit": "35d3a67c62df4b22d7167da3d73dd9dbc4905e66" + } + } } ] } diff --git a/catalog-provenance.json b/catalog-provenance.json index 10bfa3e0b..e30a9e6aa 100644 --- a/catalog-provenance.json +++ b/catalog-provenance.json @@ -61,22 +61,44 @@ "sourcePath": "infra-templates/scheduler", "originStatus": "supported", "maintainedRelease": { - "reference": "ghcr.io/pasturestack/resource-scheduler:v0.8.19", - "releaseTag": "v0.8.19", - "releaseUrl": "https://github.com/PastureStack/resource-scheduler/releases/tag/v0.8.19", + "reference": "ghcr.io/pasturestack/resource-scheduler:v0.8.20", + "releaseTag": "v0.8.20", + "releaseUrl": "https://github.com/PastureStack/resource-scheduler/releases/tag/v0.8.20", "sourceRepository": "https://github.com/PastureStack/resource-scheduler", - "sourceCommit": "d1720ddb65a285ed615f1461ccb44e50c2ad67a7", - "manifestDigest": "sha256:46dfecc72fc1fceab5c66f881f46449874b6a084a208f59c6ef1184a0d15c3f9", + "sourceCommit": "35d3a67c62df4b22d7167da3d73dd9dbc4905e66", + "manifestDigest": "sha256:e5a389273344585fca5c4513060e5289b30ca13046d8ec286b8563952f1325d4", "sbom": { "format": "CycloneDX", - "url": "https://github.com/PastureStack/resource-scheduler/releases/download/v0.8.19/resource-scheduler-0.8.19-image.cdx.json", - "sha256": "1ffbad2e58a5eaa5b7d72c83f8d8586f9f0eda337aacc41eb8d05a106951dc6e", + "url": "https://github.com/PastureStack/resource-scheduler/releases/download/v0.8.20/resource-scheduler-0.8.20-image.cdx.json", + "sha256": "56de083886f393483d988c210d307d71a0b9252b5d25a36095b2161bbab15e91", "provenance": { "verified": true, "predicateType": "https://slsa.dev/provenance/v1", "signerWorkflow": "PastureStack/resource-scheduler/.github/workflows/release.yml", - "sourceRef": "refs/tags/v0.8.19", - "sourceCommit": "d1720ddb65a285ed615f1461ccb44e50c2ad67a7" + "sourceRef": "refs/tags/v0.8.20", + "sourceCommit": "35d3a67c62df4b22d7167da3d73dd9dbc4905e66" + } + } + }, + "retainedReleases": { + "v0.8.19": { + "reference": "ghcr.io/pasturestack/resource-scheduler:v0.8.19", + "releaseTag": "v0.8.19", + "releaseUrl": "https://github.com/PastureStack/resource-scheduler/releases/tag/v0.8.19", + "sourceRepository": "https://github.com/PastureStack/resource-scheduler", + "sourceCommit": "d1720ddb65a285ed615f1461ccb44e50c2ad67a7", + "manifestDigest": "sha256:46dfecc72fc1fceab5c66f881f46449874b6a084a208f59c6ef1184a0d15c3f9", + "sbom": { + "format": "CycloneDX", + "url": "https://github.com/PastureStack/resource-scheduler/releases/download/v0.8.19/resource-scheduler-0.8.19-image.cdx.json", + "sha256": "1ffbad2e58a5eaa5b7d72c83f8d8586f9f0eda337aacc41eb8d05a106951dc6e", + "provenance": { + "verified": true, + "predicateType": "https://slsa.dev/provenance/v1", + "signerWorkflow": "PastureStack/resource-scheduler/.github/workflows/release.yml", + "sourceRef": "refs/tags/v0.8.19", + "sourceCommit": "d1720ddb65a285ed615f1461ccb44e50c2ad67a7" + } } } } diff --git a/infra-templates/amazon-ebs-storage/3/README.md b/infra-templates/amazon-ebs-storage/3/README.md new file mode 100644 index 000000000..75f250e5b --- /dev/null +++ b/infra-templates/amazon-ebs-storage/3/README.md @@ -0,0 +1,29 @@ +# PastureStack Amazon EBS Storage + +This infrastructure entry installs a global Amazon Elastic Block Store volume +driver on each managed host. + +Existing volumes are the safe default. Supply a `volumeID` in the workload +volume options. Cloud provisioning is disabled unless an administrator +explicitly enables it while installing the infrastructure stack. When enabled, +new volumes are encrypted by default and the driver may create, format, detach, +and delete resources according to the volume lifecycle. + +IAM instance profiles are preferred. Static or temporary credentials are +optional compatibility inputs and remain visible to administrators through +container configuration, so use the narrowest practical permissions. + +```yaml +version: '2' +services: + app: + image: example.invalid/application:v1.0.0 + volumes: + - data:/data +volumes: + data: + driver: pasturestack-ebs + driver_opts: + volumeID: vol-0123456789abcdef0 + fs-type: ext4 +``` diff --git a/infra-templates/amazon-ebs-storage/3/README.zh-TW.md b/infra-templates/amazon-ebs-storage/3/README.zh-TW.md new file mode 100644 index 000000000..3f5146636 --- /dev/null +++ b/infra-templates/amazon-ebs-storage/3/README.zh-TW.md @@ -0,0 +1,28 @@ +# PastureStack Amazon EBS 儲存空間 + +此基礎架構範本會在每台受管主機上安裝全域的 Amazon Elastic Block +Store 磁碟區驅動程式。 + +預設只使用既有磁碟區,這是較安全的設定。請在工作負載的磁碟區選項 +中提供 `volumeID`。除非管理者安裝此基礎架構堆疊時明確啟用,否則 +不會建立雲端資源。啟用後,新建磁碟區預設會加密,驅動程式也能依照 +磁碟區生命週期建立、格式化、卸離及刪除資源。 + +建議優先使用 IAM 執行個體設定檔。為了相容性,也可提供固定或臨時 +登入資訊,但管理者仍能從容器設定中看到這些值,因此請授予最小必要 +權限。 + +```yaml +version: '2' +services: + app: + image: example.invalid/application:v1.0.0 + volumes: + - data:/data +volumes: + data: + driver: pasturestack-ebs + driver_opts: + volumeID: vol-0123456789abcdef0 + fs-type: ext4 +``` diff --git a/infra-templates/amazon-ebs-storage/3/docker-compose.yml b/infra-templates/amazon-ebs-storage/3/docker-compose.yml new file mode 100644 index 000000000..bd3d7f42e --- /dev/null +++ b/infra-templates/amazon-ebs-storage/3/docker-compose.yml @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: MIT +version: '2' +services: + amazon-ebs-storage-driver: + image: ghcr.io/pasturestack/ebs-storage-driver:v0.11.1 + privileged: true + network_mode: host + environment: + ALLOW_CLOUD_PROVISIONING: '${ALLOW_CLOUD_PROVISIONING}' + AWS_ACCESS_KEY_ID: '${AWS_ACCESS_KEY_ID}' + AWS_SECRET_ACCESS_KEY: '${AWS_SECRET_ACCESS_KEY}' + AWS_SESSION_TOKEN: '${AWS_SESSION_TOKEN}' + AWS_REGION: '${AWS_REGION}' + PASTURESTACK_DEBUG: '${PASTURESTACK_DEBUG}' + labels: + io.rancher.scheduler.global: 'true' + io.rancher.container.create_agent: 'true' + io.rancher.container.agent.role: environment + io.rancher.container.dns: 'true' + volumes: + - /run:/run + - /var/run:/var/run + - /dev:/host/dev + - /var/lib/rancher/volumes:/var/lib/pasturestack/volumes:shared + logging: + driver: json-file + options: + max-size: 25m + max-file: '2' diff --git a/infra-templates/amazon-ebs-storage/3/rancher-compose.yml b/infra-templates/amazon-ebs-storage/3/rancher-compose.yml new file mode 100644 index 000000000..70ef28ce9 --- /dev/null +++ b/infra-templates/amazon-ebs-storage/3/rancher-compose.yml @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: MIT +.catalog: + name: PastureStack Amazon EBS Storage + version: v0.11.1 + description: Attach existing Amazon EBS volumes, with opt-in encrypted volume provisioning. + minimum_rancher_version: v1.6.29-rc1 + labels: + io.pasturestack.catalog.question.aws_region.label.zh-tw: 'AWS 區域' + io.pasturestack.catalog.question.aws_region.description.zh-tw: '若受管主機可透過 EC2 IMDSv2 取得所在區域,可留空。' + io.pasturestack.catalog.question.aws_access_key_id.label.zh-tw: 'AWS 存取金鑰識別碼' + io.pasturestack.catalog.question.aws_access_key_id.description.zh-tw: '受管主機使用 IAM 執行個體設定檔時可留空。' + io.pasturestack.catalog.question.aws_secret_access_key.label.zh-tw: 'AWS 私密存取金鑰' + io.pasturestack.catalog.question.aws_secret_access_key.description.zh-tw: '受管主機使用 IAM 執行個體設定檔時可留空。' + io.pasturestack.catalog.question.aws_session_token.label.zh-tw: 'AWS 工作階段權杖' + io.pasturestack.catalog.question.aws_session_token.description.zh-tw: '使用 AWS 臨時登入資訊時提供的選用權杖。' + io.pasturestack.catalog.question.allow_cloud_provisioning.label.zh-tw: '允許建立及刪除雲端資源' + io.pasturestack.catalog.question.allow_cloud_provisioning.description.zh-tw: '保持停用時只使用既有 EBS 磁碟區;啟用後可建立加密磁碟區,並允許格式化、卸離及刪除。' + io.pasturestack.catalog.question.pasturestack_debug.label.zh-tw: '啟用除錯日誌' + io.pasturestack.catalog.question.pasturestack_debug.description.zh-tw: '記錄較詳細的儲存驅動程式診斷資訊。' + questions: + - variable: AWS_REGION + label: Amazon region + description: Optional when the managed hosts can read their region through EC2 IMDSv2. + type: string + default: '' + required: false + - variable: AWS_ACCESS_KEY_ID + label: AWS access key ID + description: Optional when the managed hosts use an IAM instance profile. + type: string + default: '' + required: false + - variable: AWS_SECRET_ACCESS_KEY + label: AWS secret access key + description: Optional when the managed hosts use an IAM instance profile. + type: password + default: '' + required: false + - variable: AWS_SESSION_TOKEN + label: AWS session token + description: Optional token for temporary AWS credentials. + type: password + default: '' + required: false + - variable: ALLOW_CLOUD_PROVISIONING + label: Allow cloud resource provisioning and deletion + description: Keep disabled to use existing EBS volumes only. Enabling this permits encrypted volume creation, formatting, detachment, and deletion. + type: boolean + default: false + required: true + - variable: PASTURESTACK_DEBUG + label: Enable debug logging + description: Enable verbose storage-driver diagnostics. + type: boolean + default: false + required: true + +amazon-ebs-storage-driver: + storage_driver: + name: pasturestack-ebs + description: Amazon EBS block storage + scope: environment + volume_access_mode: singleHostRW + start_on_create: true diff --git a/infra-templates/amazon-ebs-storage/config.yml b/infra-templates/amazon-ebs-storage/config.yml index 869a8e6ed..f57acd2b3 100644 --- a/infra-templates/amazon-ebs-storage/config.yml +++ b/infra-templates/amazon-ebs-storage/config.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT name: Amazon EBS Storage description: Attach existing Amazon EBS volumes, with opt-in encrypted volume provisioning. -version: v0.10.0 +version: v0.11.1 category: Storage maintainer: PastureStack contributors license: MIT template; Apache-2.0 image and third-party package licenses apply diff --git a/infra-templates/amazon-efs-storage/3/README.md b/infra-templates/amazon-efs-storage/3/README.md new file mode 100644 index 000000000..13ca0a5e1 --- /dev/null +++ b/infra-templates/amazon-efs-storage/3/README.md @@ -0,0 +1,30 @@ +# PastureStack Amazon EFS Storage + +This infrastructure entry installs a global Amazon Elastic File System volume +driver on each managed host. + +Existing filesystems are the safe default. Supply an `fsid` in the workload +volume options. Cloud provisioning is disabled unless an administrator +explicitly enables it while installing the infrastructure stack. Provisioning +requires an operator-selected subnet and security group; this driver does not +create a security group or add unrestricted NFS ingress. + +IAM instance profiles are preferred. Static or temporary credentials are +optional compatibility inputs and remain visible to administrators through +container configuration, so use the narrowest practical permissions. + +```yaml +version: '2' +services: + app: + image: example.invalid/application:v1.0.0 + volumes: + - shared:/data +volumes: + shared: + driver: pasturestack-efs + driver_opts: + fsid: fs-0123456789abcdef0 + export: / + mntOptions: vers=4.1 +``` diff --git a/infra-templates/amazon-efs-storage/3/README.zh-TW.md b/infra-templates/amazon-efs-storage/3/README.zh-TW.md new file mode 100644 index 000000000..883041e26 --- /dev/null +++ b/infra-templates/amazon-efs-storage/3/README.zh-TW.md @@ -0,0 +1,30 @@ +# PastureStack Amazon EFS 儲存空間 + +此基礎架構範本會在每台受管主機上安裝全域的 Amazon Elastic File +System 磁碟區驅動程式。 + +預設只使用既有檔案系統,這是較安全的設定。請在工作負載的磁碟區 +選項中提供 `fsid`。除非管理者安裝此基礎架構堆疊時明確啟用,否則 +不會建立雲端資源。啟用資源建立功能時,必須由管理者指定子網路與 +安全性群組;此驅動程式不會建立安全性群組,也不會開放未受限制的 +NFS 連入流量。 + +建議優先使用 IAM 執行個體設定檔。為了相容性,也可提供固定或臨時 +登入資訊,但管理者仍能從容器設定中看到這些值,因此請授予最小必要 +權限。 + +```yaml +version: '2' +services: + app: + image: example.invalid/application:v1.0.0 + volumes: + - shared:/data +volumes: + shared: + driver: pasturestack-efs + driver_opts: + fsid: fs-0123456789abcdef0 + export: / + mntOptions: vers=4.1 +``` diff --git a/infra-templates/amazon-efs-storage/3/docker-compose.yml b/infra-templates/amazon-efs-storage/3/docker-compose.yml new file mode 100644 index 000000000..d754dfd72 --- /dev/null +++ b/infra-templates/amazon-efs-storage/3/docker-compose.yml @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: MIT +version: '2' +services: + amazon-efs-storage-driver: + image: ghcr.io/pasturestack/efs-storage-driver:v0.11.1 + privileged: true + network_mode: host + environment: + ALLOW_CLOUD_PROVISIONING: '${ALLOW_CLOUD_PROVISIONING}' + AWS_ACCESS_KEY_ID: '${AWS_ACCESS_KEY_ID}' + AWS_SECRET_ACCESS_KEY: '${AWS_SECRET_ACCESS_KEY}' + AWS_SESSION_TOKEN: '${AWS_SESSION_TOKEN}' + AWS_REGION: '${AWS_REGION}' + EFS_SUBNET_ID: '${EFS_SUBNET_ID}' + EFS_SECURITY_GROUP_ID: '${EFS_SECURITY_GROUP_ID}' + PASTURESTACK_DEBUG: '${PASTURESTACK_DEBUG}' + labels: + io.rancher.scheduler.global: 'true' + io.rancher.container.create_agent: 'true' + io.rancher.container.agent.role: environment + io.rancher.container.dns: 'true' + volumes: + - /run:/run + - /var/run:/var/run + - /dev:/host/dev + - /var/lib/rancher/volumes:/var/lib/pasturestack/volumes:shared + logging: + driver: json-file + options: + max-size: 25m + max-file: '2' diff --git a/infra-templates/amazon-efs-storage/3/rancher-compose.yml b/infra-templates/amazon-efs-storage/3/rancher-compose.yml new file mode 100644 index 000000000..eb300007c --- /dev/null +++ b/infra-templates/amazon-efs-storage/3/rancher-compose.yml @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: MIT +.catalog: + name: PastureStack Amazon EFS Storage + version: v0.11.1 + description: Mount existing Amazon EFS filesystems, with controlled opt-in provisioning. + minimum_rancher_version: v1.6.15-rc1 + labels: + io.pasturestack.catalog.question.aws_region.label.zh-tw: 'AWS 區域' + io.pasturestack.catalog.question.aws_region.description.zh-tw: '若受管主機可透過 EC2 IMDSv2 取得所在區域,可留空。' + io.pasturestack.catalog.question.aws_access_key_id.label.zh-tw: 'AWS 存取金鑰識別碼' + io.pasturestack.catalog.question.aws_access_key_id.description.zh-tw: '受管主機使用 IAM 執行個體設定檔時可留空。' + io.pasturestack.catalog.question.aws_secret_access_key.label.zh-tw: 'AWS 私密存取金鑰' + io.pasturestack.catalog.question.aws_secret_access_key.description.zh-tw: '受管主機使用 IAM 執行個體設定檔時可留空。' + io.pasturestack.catalog.question.aws_session_token.label.zh-tw: 'AWS 工作階段權杖' + io.pasturestack.catalog.question.aws_session_token.description.zh-tw: '使用 AWS 臨時登入資訊時提供的選用權杖。' + io.pasturestack.catalog.question.allow_cloud_provisioning.label.zh-tw: '允許建立及刪除雲端資源' + io.pasturestack.catalog.question.allow_cloud_provisioning.description.zh-tw: '保持停用時只使用既有 EFS 檔案系統;啟用後可建立及刪除加密檔案系統與掛載目標。' + io.pasturestack.catalog.question.efs_subnet_id.label.zh-tw: 'EFS 掛載目標子網路識別碼' + io.pasturestack.catalog.question.efs_subnet_id.description.zh-tw: '只有啟用雲端資源建立功能時才需要。' + io.pasturestack.catalog.question.efs_security_group_id.label.zh-tw: 'EFS 掛載目標安全性群組識別碼' + io.pasturestack.catalog.question.efs_security_group_id.description.zh-tw: '只有啟用雲端資源建立功能時才需要;選取的群組只能允許受信任用戶端使用 NFS。' + io.pasturestack.catalog.question.pasturestack_debug.label.zh-tw: '啟用除錯日誌' + io.pasturestack.catalog.question.pasturestack_debug.description.zh-tw: '記錄較詳細的儲存驅動程式診斷資訊。' + questions: + - variable: AWS_REGION + label: Amazon region + description: Optional when the managed hosts can read their region through EC2 IMDSv2. + type: string + default: '' + required: false + - variable: AWS_ACCESS_KEY_ID + label: AWS access key ID + description: Optional when the managed hosts use an IAM instance profile. + type: string + default: '' + required: false + - variable: AWS_SECRET_ACCESS_KEY + label: AWS secret access key + description: Optional when the managed hosts use an IAM instance profile. + type: password + default: '' + required: false + - variable: AWS_SESSION_TOKEN + label: AWS session token + description: Optional token for temporary AWS credentials. + type: password + default: '' + required: false + - variable: ALLOW_CLOUD_PROVISIONING + label: Allow cloud resource provisioning and deletion + description: Keep disabled to use existing EFS filesystems only. Enabling this permits encrypted filesystem and mount-target creation and deletion. + type: boolean + default: false + required: true + - variable: EFS_SUBNET_ID + label: EFS mount-target subnet ID + description: Required only when cloud provisioning is enabled. + type: string + default: '' + required: false + - variable: EFS_SECURITY_GROUP_ID + label: EFS mount-target security group ID + description: Required only when cloud provisioning is enabled. The selected group must permit NFS only from trusted clients. + type: string + default: '' + required: false + - variable: PASTURESTACK_DEBUG + label: Enable debug logging + description: Enable verbose storage-driver diagnostics. + type: boolean + default: false + required: true + +amazon-efs-storage-driver: + storage_driver: + name: pasturestack-efs + description: Amazon EFS shared file storage + scope: environment + volume_access_mode: multiHostRW + start_on_create: true diff --git a/infra-templates/amazon-efs-storage/config.yml b/infra-templates/amazon-efs-storage/config.yml index 30bec6fa2..fc8461fea 100644 --- a/infra-templates/amazon-efs-storage/config.yml +++ b/infra-templates/amazon-efs-storage/config.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT name: Amazon EFS Storage description: Mount existing Amazon EFS filesystems, with controlled opt-in provisioning. -version: v0.10.0 +version: v0.11.1 category: Storage maintainer: PastureStack contributors license: MIT template; Apache-2.0 image and third-party package licenses apply diff --git a/infra-templates/nfs-storage/3/README.md b/infra-templates/nfs-storage/3/README.md new file mode 100644 index 000000000..2d2f429f3 --- /dev/null +++ b/infra-templates/nfs-storage/3/README.md @@ -0,0 +1,46 @@ +# PastureStack NFS Storage + +This infrastructure entry installs a global Docker volume driver for NFS +version 3 and version 4. Each managed volume uses a validated subdirectory of +the configured export base. + +Data is retained when a volume is removed unless an operator explicitly selects +`purge`. Purging is restricted to the driver's validated, owned subdirectory. +A volume configured with a direct `host` and `export` reference is always +treated as externally managed and is never recursively deleted. + +## Default configuration + +Configure the NFS server, exported base directory, mount options, and protocol +version when the stack is installed. Workloads then reference the +`pasturestack-nfs` volume driver: + +```yaml +version: '2' +services: + app: + image: example.invalid/application:v1.0.0 + volumes: + - data:/data +volumes: + data: + driver: pasturestack-nfs +``` + +## Per-volume configuration + +An individual volume may use a different NFS server and export base: + +```yaml +volumes: + data: + driver: pasturestack-nfs + driver_opts: + host: nfs.internal.example + exportBase: /exports/applications + mntOptions: nfsvers=4,proto=tcp + onRemove: retain +``` + +A direct `export` reference mounts the named export without creating a +subdirectory and always retains the underlying data. diff --git a/infra-templates/nfs-storage/3/README.zh-TW.md b/infra-templates/nfs-storage/3/README.zh-TW.md new file mode 100644 index 000000000..650833728 --- /dev/null +++ b/infra-templates/nfs-storage/3/README.zh-TW.md @@ -0,0 +1,44 @@ +# PastureStack NFS 儲存空間 + +此基礎架構範本會在每台受管主機上安裝支援 NFS 第 3 版與第 4 版的 +全域 Docker 磁碟區驅動程式。每個受管磁碟區都使用已驗證、位於設定 +匯出基底目錄下的子目錄。 + +移除磁碟區時預設保留資料;只有管理者明確選擇 `purge` 才會清除。 +清除範圍只限於經驅動程式驗證且由驅動程式管理的子目錄。若磁碟區直接 +指定 `host` 與 `export`,系統一律視為外部管理,不會遞迴刪除資料。 + +## 預設設定 + +安裝堆疊時請設定 NFS 伺服器、匯出基底目錄、掛載選項及協定版本。 +工作負載即可引用 `pasturestack-nfs` 磁碟區驅動程式: + +```yaml +version: '2' +services: + app: + image: example.invalid/application:v1.0.0 + volumes: + - data:/data +volumes: + data: + driver: pasturestack-nfs +``` + +## 個別磁碟區設定 + +個別磁碟區可使用不同的 NFS 伺服器及匯出基底目錄: + +```yaml +volumes: + data: + driver: pasturestack-nfs + driver_opts: + host: nfs.internal.example + exportBase: /exports/applications + mntOptions: nfsvers=4,proto=tcp + onRemove: retain +``` + +直接指定 `export` 時,系統會直接掛載該匯出目錄,不會建立子目錄, +而且永遠保留底層資料。 diff --git a/infra-templates/nfs-storage/3/docker-compose.yml b/infra-templates/nfs-storage/3/docker-compose.yml new file mode 100644 index 000000000..8798c5a9d --- /dev/null +++ b/infra-templates/nfs-storage/3/docker-compose.yml @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: MIT +version: '2' +services: + nfs-storage-driver: + image: ghcr.io/pasturestack/nfs-storage-driver:v0.11.1 + privileged: true + network_mode: host + environment: + NFS_SERVER: '${NFS_SERVER}' + MOUNT_DIR: '${MOUNT_DIR}' + MOUNT_OPTS: '${MOUNT_OPTS},${NFS_VERS}' + ON_REMOVE: '${ON_REMOVE}' + PASTURESTACK_DEBUG: '${PASTURESTACK_DEBUG}' + labels: + io.rancher.scheduler.global: 'true' + io.rancher.container.create_agent: 'true' + io.rancher.container.agent.role: environment + io.rancher.container.dns: 'true' + volumes: + - /run:/run + - /var/run:/var/run + - /dev:/host/dev + - /var/lib/rancher/volumes:/var/lib/pasturestack/volumes:shared + logging: + driver: json-file + options: + max-size: 25m + max-file: '2' diff --git a/infra-templates/nfs-storage/3/rancher-compose.yml b/infra-templates/nfs-storage/3/rancher-compose.yml new file mode 100644 index 000000000..a10c9bfb8 --- /dev/null +++ b/infra-templates/nfs-storage/3/rancher-compose.yml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: MIT +.catalog: + name: PastureStack NFS Storage + version: v0.11.1 + description: Provide NFS v3 and v4 Docker volumes with safe data-retention defaults. + minimum_rancher_version: v1.6.15-rc1 + labels: + io.pasturestack.catalog.question.nfs_server.label.zh-tw: 'NFS 伺服器' + io.pasturestack.catalog.question.nfs_server.description.zh-tw: '預設 NFS 伺服器的 IP 位址或 DNS 名稱。' + io.pasturestack.catalog.question.mount_dir.label.zh-tw: '匯出基底目錄' + io.pasturestack.catalog.question.mount_dir.description.zh-tw: '預設匯出基底目錄的絕對路徑。' + io.pasturestack.catalog.question.mount_opts.label.zh-tw: '掛載選項' + io.pasturestack.catalog.question.mount_opts.description.zh-tw: 'NFS 版本以外的掛載選項,以半形逗號分隔。' + io.pasturestack.catalog.question.nfs_vers.label.zh-tw: 'NFS 版本' + io.pasturestack.catalog.question.nfs_vers.description.zh-tw: '預設使用的 NFS 協定版本。' + io.pasturestack.catalog.question.on_remove.label.zh-tw: '資料移除原則' + io.pasturestack.catalog.question.on_remove.description.zh-tw: '預設保留資料;只有明確選擇清除時,才會刪除驅動程式所管理的磁碟區子目錄。' + io.pasturestack.catalog.question.pasturestack_debug.label.zh-tw: '啟用除錯日誌' + io.pasturestack.catalog.question.pasturestack_debug.description.zh-tw: '記錄較詳細的儲存驅動程式診斷資訊。' + questions: + - variable: NFS_SERVER + label: NFS server + description: IP address or DNS name of the default NFS server. + type: string + required: true + - variable: MOUNT_DIR + label: Export base directory + description: Absolute path of the default exported base directory. + type: string + required: true + - variable: MOUNT_OPTS + label: Mount options + description: Comma-delimited mount options other than the NFS version. + type: string + default: proto=tcp + required: true + - variable: NFS_VERS + label: NFS version + description: Default NFS protocol version. + type: enum + default: nfsvers=4 + required: true + options: + - nfsvers=4 + - nfsvers=3 + - variable: ON_REMOVE + label: Data removal policy + description: Retain data by default, or explicitly purge the driver's owned volume subdirectory. + type: enum + default: retain + required: true + options: + - retain + - purge + - variable: PASTURESTACK_DEBUG + label: Enable debug logging + description: Enable verbose storage-driver diagnostics. + type: boolean + default: false + required: true + +nfs-storage-driver: + storage_driver: + name: pasturestack-nfs + scope: environment + volume_access_mode: multiHostRW diff --git a/infra-templates/nfs-storage/config.yml b/infra-templates/nfs-storage/config.yml index f4d423f94..b22af344c 100644 --- a/infra-templates/nfs-storage/config.yml +++ b/infra-templates/nfs-storage/config.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT name: NFS Storage description: Provide NFS v3 and v4 Docker volumes with safe data-retention defaults. -version: v0.10.0 +version: v0.11.1 category: Storage maintainer: PastureStack contributors license: MIT template; Apache-2.0 image and third-party package licenses apply diff --git a/infra-templates/resource-scheduler/6/README.md b/infra-templates/resource-scheduler/6/README.md new file mode 100644 index 000000000..76f1b5dd6 --- /dev/null +++ b/infra-templates/resource-scheduler/6/README.md @@ -0,0 +1,24 @@ + + +# Resource Scheduler v0.8.19 + +This template deploys the functional PastureStack resource scheduler as the +control plane's scheduling agent. It consumes the established control-plane +event and Metadata contracts while using the native PastureStack executable, +debug option, public image, and semantic version tag. + +The runtime executes as UID and GID `10001:10001`. Only the scheduler binary +has permission to bind the compatibility health-check port. + +This version reconnects the control-plane event subscriber after a clean +disconnect or an error and restarts the Metadata watcher after an error or a +recovered panic. + +`/healthcheck` reports process liveness. `/readiness` reports whether the +control-plane and Metadata dependencies are currently available. A planned +control-plane restart can therefore make the service temporarily unready +without replacing the scheduler container. + +This dependency-only security update uses the official Go and Ubuntu fixes. +Scheduling, questions, credentials, and health-check contracts are unchanged. +Packaged CI health evidence does not qualify a managed-system upgrade or rollback. diff --git a/infra-templates/resource-scheduler/6/README.zh-TW.md b/infra-templates/resource-scheduler/6/README.zh-TW.md new file mode 100644 index 000000000..cb1bfeb82 --- /dev/null +++ b/infra-templates/resource-scheduler/6/README.zh-TW.md @@ -0,0 +1,20 @@ + + +# 資源排程器 v0.8.19 + +此範本會把可正常運作的 PastureStack 資源排程器部署成控制平面的 +排程代理程式。排程器使用既有的控制平面事件及中繼資料契約,同時採用 +原生 PastureStack 執行檔、除錯選項、公開映像與語意化版本標籤。 + +執行環境使用 UID/GID `10001:10001`。只有排程器執行檔具備綁定 +相容健康檢查連接埠的權限。 + +此版本會在控制平面事件訂閱正常中斷或發生錯誤後重新連線,並在中繼 +資料監看發生錯誤或已攔截的異常後重新啟動監看程序。 + +`/healthcheck` 只回報處理程序是否存活;`/readiness` 則回報控制平面與 +中繼資料相依服務目前是否可用。因此,控制平面進行計畫性重新啟動時, +排程器可以暫時呈現尚未就緒,而不會因此被替換容器。 + +此次僅採用 Go 與 Ubuntu 官方相依套件安全修補,排程、問題欄位、憑證及 +健康檢查契約均維持不變。成品 CI 健康驗證不代表已完成受管系統升級或回復驗收。 diff --git a/infra-templates/resource-scheduler/6/docker-compose.yml b/infra-templates/resource-scheduler/6/docker-compose.yml new file mode 100644 index 000000000..099f6749e --- /dev/null +++ b/infra-templates/resource-scheduler/6/docker-compose.yml @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: MIT +version: '2' +services: + resource-scheduler: + image: ghcr.io/pasturestack/resource-scheduler:v0.8.20 + command: resource-scheduler --metadata-address 169.254.169.250 + environment: + PASTURESTACK_DEBUG: '${PASTURESTACK_DEBUG}' + labels: + io.rancher.container.create_agent: 'true' + io.rancher.container.agent_service.scheduling: 'true' + logging: + driver: json-file + options: + max-size: 25m + max-file: '2' diff --git a/infra-templates/resource-scheduler/6/rancher-compose.yml b/infra-templates/resource-scheduler/6/rancher-compose.yml new file mode 100644 index 000000000..7a95147d5 --- /dev/null +++ b/infra-templates/resource-scheduler/6/rancher-compose.yml @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: MIT +.catalog: + name: Resource Scheduler + description: Schedule native workloads from control-plane events and current Metadata state. + version: v0.8.20 + minimum_rancher_version: v1.6.26-rc1 + labels: + io.pasturestack.catalog.question.pasturestack_debug.label.zh-tw: '啟用除錯日誌' + io.pasturestack.catalog.question.pasturestack_debug.description.zh-tw: '記錄較詳細的排程器診斷資訊。' + io.pasturestack.catalog.question.healthcheck_interval.label.zh-tw: '健康檢查間隔' + io.pasturestack.catalog.question.healthcheck_interval.description.zh-tw: '兩次健康檢查之間的毫秒數。' + io.pasturestack.catalog.question.healthcheck_init_timeout.label.zh-tw: '初始化逾時' + io.pasturestack.catalog.question.healthcheck_init_timeout.description.zh-tw: '等待排程器初次就緒的毫秒數上限。' + io.pasturestack.catalog.question.healthcheck_reinit_timeout.label.zh-tw: '重新初始化逾時' + io.pasturestack.catalog.question.healthcheck_reinit_timeout.description.zh-tw: '等待排程器重新初始化的毫秒數上限。' + io.pasturestack.catalog.question.healthcheck_response_timeout.label.zh-tw: '回應逾時' + io.pasturestack.catalog.question.healthcheck_response_timeout.description.zh-tw: '等待單次健康檢查回應的毫秒數上限。' + io.pasturestack.catalog.question.healthcheck_unhealthy_threshold.label.zh-tw: '判定為不健康的失敗次數' + io.pasturestack.catalog.question.healthcheck_unhealthy_threshold.description.zh-tw: '連續失敗達到此次數時,將服務標示為不健康。' + io.pasturestack.catalog.question.healthcheck_healthy_threshold.label.zh-tw: '判定為健康的成功次數' + io.pasturestack.catalog.question.healthcheck_healthy_threshold.description.zh-tw: '連續成功達到此次數時,將服務標示為健康。' + questions: + - variable: PASTURESTACK_DEBUG + label: Enable debug logging + description: Enable verbose scheduler diagnostics. + type: boolean + default: false + required: true + - variable: HEALTHCHECK_INTERVAL + label: Health-check interval + description: Milliseconds between health checks. + type: int + default: 2000 + required: true + - variable: HEALTHCHECK_INIT_TIMEOUT + label: Initialization timeout + description: Milliseconds allowed for initial scheduler readiness. + type: int + default: 10000 + required: true + - variable: HEALTHCHECK_REINIT_TIMEOUT + label: Reinitialization timeout + description: Milliseconds allowed for scheduler reinitialization. + type: int + default: 10000 + required: true + - variable: HEALTHCHECK_RESPONSE_TIMEOUT + label: Response timeout + description: Milliseconds allowed for an individual health-check response. + type: int + default: 30000 + required: true + - variable: HEALTHCHECK_UNHEALTHY_THRESHOLD + label: Unhealthy threshold + description: Consecutive failed checks required to mark the service unhealthy. + type: int + default: 3 + required: true + - variable: HEALTHCHECK_HEALTHY_THRESHOLD + label: Healthy threshold + description: Consecutive successful checks required to mark the service healthy. + type: int + default: 2 + required: true + +resource-scheduler: + health_check: + request_line: GET /healthcheck HTTP/1.0 + port: 80 + interval: ${HEALTHCHECK_INTERVAL} + initializing_timeout: ${HEALTHCHECK_INIT_TIMEOUT} + reinitializing_timeout: ${HEALTHCHECK_REINIT_TIMEOUT} + response_timeout: ${HEALTHCHECK_RESPONSE_TIMEOUT} + unhealthy_threshold: ${HEALTHCHECK_UNHEALTHY_THRESHOLD} + healthy_threshold: ${HEALTHCHECK_HEALTHY_THRESHOLD} diff --git a/infra-templates/resource-scheduler/config.yml b/infra-templates/resource-scheduler/config.yml index 6985b36bb..93478eac6 100644 --- a/infra-templates/resource-scheduler/config.yml +++ b/infra-templates/resource-scheduler/config.yml @@ -1,6 +1,6 @@ # SPDX-License-Identifier: MIT name: Resource Scheduler -version: v0.8.19 +version: v0.8.20 category: System description: Schedule native workloads from control-plane events and current Metadata state. projectURL: https://github.com/PastureStack/resource-scheduler diff --git a/integration/core/test_catalog.py b/integration/core/test_catalog.py index 97104e213..2de472350 100644 --- a/integration/core/test_catalog.py +++ b/integration/core/test_catalog.py @@ -169,17 +169,17 @@ def test_catalog_list(): assert by_folder[('infra', 'amazon-ebs-storage')][ 'name'] == 'Amazon EBS Storage' assert by_folder[('infra', 'amazon-ebs-storage')][ - 'defaultVersion'] == 'v0.10.0' + 'defaultVersion'] == 'v0.11.1' assert by_folder[('infra', 'amazon-ebs-storage')][ 'links']['defaultVersion'].endswith( - ':2') + ':3') assert by_folder[('infra', 'amazon-efs-storage')][ 'name'] == 'Amazon EFS Storage' assert by_folder[('infra', 'amazon-efs-storage')][ - 'defaultVersion'] == 'v0.10.0' + 'defaultVersion'] == 'v0.11.1' assert by_folder[('infra', 'amazon-efs-storage')][ 'links']['defaultVersion'].endswith( - ':2') + ':3') assert by_folder[('infra', 'container-schedule')][ 'name'] == 'Container Schedule' assert by_folder[('infra', 'container-schedule')][ @@ -239,10 +239,10 @@ def test_catalog_list(): assert by_folder[('infra', 'nfs-storage')][ 'name'] == 'NFS Storage' assert by_folder[('infra', 'nfs-storage')][ - 'defaultVersion'] == 'v0.10.0' + 'defaultVersion'] == 'v0.11.1' assert by_folder[('infra', 'nfs-storage')][ 'links']['defaultVersion'].endswith( - ':2') + ':3') assert by_folder[('infra', 'secret-volume-driver')][ 'name'] == 'Secret Volume' assert by_folder[('infra', 'secret-volume-driver')][ @@ -266,10 +266,10 @@ def test_catalog_list(): assert by_folder[('infra', 'resource-scheduler')][ 'name'] == 'Resource Scheduler' assert by_folder[('infra', 'resource-scheduler')][ - 'defaultVersion'] == 'v0.8.19' + 'defaultVersion'] == 'v0.8.20' assert by_folder[('infra', 'resource-scheduler')][ 'links']['defaultVersion'].endswith( - ':5') + ':6') assert by_folder[('infra', 'route53-dns-sync')][ 'name'] == 'Route 53 DNS Sync' assert by_folder[('infra', 'route53-dns-sync')][ @@ -437,7 +437,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): ebs_files = ebs_version['files'] ebs_docker = ebs_files['docker-compose.yml'] ebs_platform = ebs_files['rancher-compose.yml'] - ebs_image = 'ghcr.io/pasturestack/ebs-storage-driver:v0.10.0' + ebs_image = 'ghcr.io/pasturestack/ebs-storage-driver:v0.11.1' assert ebs_docker.count('image: {}'.format(ebs_image)) == 1 assert '\n amazon-ebs-storage-driver:\n' in ebs_docker assert 'privileged: true' in ebs_docker @@ -465,7 +465,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): efs_files = efs_version['files'] efs_docker = efs_files['docker-compose.yml'] efs_platform = efs_files['rancher-compose.yml'] - efs_image = 'ghcr.io/pasturestack/efs-storage-driver:v0.10.0' + efs_image = 'ghcr.io/pasturestack/efs-storage-driver:v0.11.1' assert efs_docker.count('image: {}'.format(efs_image)) == 1 assert '\n amazon-efs-storage-driver:\n' in efs_docker assert 'privileged: true' in efs_docker @@ -765,7 +765,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): nfs_files = nfs_version['files'] nfs_docker = nfs_files['docker-compose.yml'] nfs_platform = nfs_files['rancher-compose.yml'] - nfs_image = 'ghcr.io/pasturestack/nfs-storage-driver:v0.10.0' + nfs_image = 'ghcr.io/pasturestack/nfs-storage-driver:v0.11.1' assert nfs_docker.count('image: {}'.format(nfs_image)) == 1 assert '\n nfs-storage-driver:\n' in nfs_docker assert 'privileged: true' in nfs_docker @@ -920,7 +920,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): scheduler_files = scheduler_version['files'] scheduler_docker = scheduler_files['docker-compose.yml'] scheduler_platform = scheduler_files['rancher-compose.yml'] - scheduler_image = 'ghcr.io/pasturestack/resource-scheduler:v0.8.19' + scheduler_image = 'ghcr.io/pasturestack/resource-scheduler:v0.8.20' assert scheduler_docker.count( 'image: {}'.format(scheduler_image)) == 1 assert '\n resource-scheduler:\n' in scheduler_docker @@ -1237,6 +1237,42 @@ def test_catalog_compose_shapes_are_runtime_compatible(): ), ], ), + ( + 'nfs-storage', '2', '3', + 'v0.10.0', 'v0.11.1', [ + ( + 'nfs-storage-driver:v0.10.0', + 'nfs-storage-driver:v0.11.1', + ), + ], + ), + ( + 'amazon-ebs-storage', '2', '3', + 'v0.10.0', 'v0.11.1', [ + ( + 'ebs-storage-driver:v0.10.0', + 'ebs-storage-driver:v0.11.1', + ), + ], + ), + ( + 'amazon-efs-storage', '2', '3', + 'v0.10.0', 'v0.11.1', [ + ( + 'efs-storage-driver:v0.10.0', + 'efs-storage-driver:v0.11.1', + ), + ], + ), + ( + 'resource-scheduler', '5', '6', + 'v0.8.19', 'v0.8.20', [ + ( + 'resource-scheduler:v0.8.19', + 'resource-scheduler:v0.8.20', + ), + ], + ), ]) def test_october_security_revisions_preserve_contract( template, old_number, new_number, old_version, new_version, @@ -1438,16 +1474,39 @@ def test_scheduler19_template_preserves_version4_contract(): 'PastureStack/resource-scheduler/.github/workflows/release.yml') with open(_file('catalog-provenance.json'), encoding='utf-8') as source: maintained = json.load(source)['entries'][ - 'resource-scheduler']['maintainedRelease'] + 'resource-scheduler']['retainedReleases']['v0.8.19'] assert maintained['reference'] == image assert maintained['sourceCommit'] == release['sourceCommit'] assert maintained['manifestDigest'] == release['manifestDigest'] assert maintained['sbom'] == sbom +def test_scheduler20_published_provenance_matches_current_image(): + image = 'ghcr.io/pasturestack/resource-scheduler:v0.8.20' + with open(_file('catalog-images.json'), encoding='utf-8') as source: + release = next(item for item in json.load(source)['images'] + if item['reference'] == image) + with open(_file('catalog-provenance.json'), encoding='utf-8') as source: + maintained = json.load(source)['entries'][ + 'resource-scheduler']['maintainedRelease'] + assert maintained['reference'] == image + assert maintained['sourceCommit'] == release['sourceCommit'] == ( + '35d3a67c62df4b22d7167da3d73dd9dbc4905e66') + assert maintained['manifestDigest'] == release['manifestDigest'] == ( + 'sha256:e5a389273344585fca5c4513060e5289b' + '30ca13046d8ec286b8563952f1325d4') + assert maintained['sbom'] == release['sbom'] + assert release['sbom']['sha256'] == ( + '56de083886f393483d988c210d307d71a0b' + '9252b5d25a36095b2161bbab15e91') + assert release['sbom']['provenance']['sourceRef'] == 'refs/tags/v0.8.20' + assert release['vulnerabilityScan']['fixedAvailable'] == 0 + + @pytest.mark.parametrize('number,image_tag', [ ('4', 'v0.8.18'), ('5', 'v0.8.19'), + ('6', 'v0.8.20'), ]) def test_scheduler_upgrade_versions_remain_available(number, image_tag): version = _get_json(_catalog_url( diff --git a/scripts/audit_deployable_images.py b/scripts/audit_deployable_images.py index d5d446c9b..0abdc494c 100644 --- a/scripts/audit_deployable_images.py +++ b/scripts/audit_deployable_images.py @@ -51,6 +51,8 @@ "配置文件", ) RETAINED_VERSION_LAYOUTS = { + "amazon-efs-storage": ("2", "3"), + "amazon-ebs-storage": ("2", "3"), "container-schedule": ("2", "3"), "ecr-credential-sync": ("2", "3"), "healthcheck": ("0", "1", "2"), @@ -59,10 +61,10 @@ "network-diagnostics": ("1", "2", "3"), "network-policy-manager": ("1", "2", "3", "4"), "network-services": ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"), - "nfs-storage": ("1", "2"), + "nfs-storage": ("1", "2", "3"), "per-host-subnet-network": ("2", "3", "4", "5"), "route53-dns-sync": ("2", "3"), - "resource-scheduler": ("1", "2", "3", "4", "5"), + "resource-scheduler": ("1", "2", "3", "4", "5", "6"), "secret-volume-driver": ("1", "2", "3"), "system-image-preloader": ("2", "3"), "vault-volume-driver": ("3", "4"), From b32c23f4e0a2edeb923252ed7ceaafe91ed63cb7 Mon Sep 17 00:00:00 2001 From: chen21019 <19357113+chen21019@users.noreply.github.com> Date: Fri, 23 Oct 2026 22:45:17 +0800 Subject: [PATCH 07/10] Pin published IPsec 0.14.40 in new compatibility revisions --- catalog-images.json | 26 ++++++++++++++----- .../ipsec-overlay/13/docker-compose.yml.tpl | 8 +++--- .../7/docker-compose.yml.tpl | 2 +- .../5/docker-compose.yml.tpl | 4 +-- .../6/docker-compose.yml.tpl | 6 ++--- integration/core/test_catalog.py | 14 +++++----- 6 files changed, 37 insertions(+), 23 deletions(-) diff --git a/catalog-images.json b/catalog-images.json index d886e9ff6..10589a4ce 100644 --- a/catalog-images.json +++ b/catalog-images.json @@ -1262,19 +1262,33 @@ "platforms": [ "linux/amd64" ], - "reference": "ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39", - "sourceCommit": "db0780394644c70c4756b33301d8b9d75d0149ca", - "manifestDigest": "sha256:72a9fec50190c25ff8b2cdbf954b22a58a93087d64ff15b3d2d9d2ca9526cbfe", + "reference": "ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.40", + "sourceCommit": "4711833178a05e5d225e364cce856bd108bdc707", + "manifestDigest": "sha256:1d39becf00ea540355cb60b430d5d379d38451c1b633ce0d704ef046f44f2c07", "reviewedAt": "2026-10-23", "vulnerabilityScan": { - "scope": "published runtime image", + "scope": "published runtime image, full severity", "high": 0, "critical": 0, - "evidence": "https://github.com/PastureStack/ipsec-vxlan-overlay-network/actions/runs/39963426128" + "evidence": "https://github.com/PastureStack/ipsec-vxlan-overlay-network/actions/runs/39971594096", + "low": 7, + "medium": 47, + "unknown": 0, + "secrets": 0, + "fixedAvailable": 0, + "actionable": 0, + "vendorUnfixedLowMedium": 54, + "disposition": "under_investigation", + "reportSha256": "6f68e630aadc863c6453ee71e22d1bd9e8dfed96f296f0ea5a17a6ec566444fe" }, "publicationVerification": { "source": "component owner verified anonymous manifest/config readback", - "workflowRun": "https://github.com/PastureStack/ipsec-vxlan-overlay-network/actions/runs/39963426128" + "workflowRun": "https://github.com/PastureStack/ipsec-vxlan-overlay-network/actions/runs/39971594096" + }, + "sbom": { + "format": "CycloneDX", + "url": "https://github.com/PastureStack/ipsec-vxlan-overlay-network/releases/download/v0.14.40/image-sbom.cdx.json", + "sha256": "6fb46040ae011434d88b732591e68d102d5cce7aa18d54b9e8026e92aa600c4e" } }, { diff --git a/infra-templates/ipsec-overlay/13/docker-compose.yml.tpl b/infra-templates/ipsec-overlay/13/docker-compose.yml.tpl index 86e37344a..f9c6f0638 100644 --- a/infra-templates/ipsec-overlay/13/docker-compose.yml.tpl +++ b/infra-templates/ipsec-overlay/13/docker-compose.yml.tpl @@ -3,7 +3,7 @@ version: '2' services: overlay-network: - image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39 + image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.40 command: - /bin/bash - -c @@ -18,7 +18,7 @@ services: io.rancher.network.arpsync: 'true' overlay-router: - image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39 + image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.40 command: start-ipsec.sh privileged: true network_mode: container:overlay-network @@ -47,7 +47,7 @@ services: net.ipv4.conf.default.send_redirects: '0' connectivity-check: - image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39 + image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.40 command: - ipsec-vxlan-connectivity-check - --connectivity-check-interval @@ -62,7 +62,7 @@ services: io.pasturestack.component: ipsec-overlay-connectivity cni-driver: - image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39 + image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.40 command: start-cni-driver.sh privileged: true network_mode: host diff --git a/infra-templates/layer-2-flat-network/7/docker-compose.yml.tpl b/infra-templates/layer-2-flat-network/7/docker-compose.yml.tpl index ece9eb462..68d24e1cf 100644 --- a/infra-templates/layer-2-flat-network/7/docker-compose.yml.tpl +++ b/infra-templates/layer-2-flat-network/7/docker-compose.yml.tpl @@ -3,7 +3,7 @@ version: '2' services: layer-2-flat-cni: - image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39 + image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.40 privileged: true network_mode: host pid: host diff --git a/infra-templates/per-host-subnet-network/5/docker-compose.yml.tpl b/infra-templates/per-host-subnet-network/5/docker-compose.yml.tpl index 6be66d00a..d139bcc86 100644 --- a/infra-templates/per-host-subnet-network/5/docker-compose.yml.tpl +++ b/infra-templates/per-host-subnet-network/5/docker-compose.yml.tpl @@ -3,7 +3,7 @@ version: '2' services: per-host-subnet-controller: - image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39 + image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.40 command: per-host-subnet privileged: true network_mode: host @@ -25,7 +25,7 @@ services: max-file: '2' per-host-subnet-cni: - image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39 + image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.40 command: start-cni-driver.sh privileged: true network_mode: host diff --git a/infra-templates/vxlan-overlay-network/6/docker-compose.yml.tpl b/infra-templates/vxlan-overlay-network/6/docker-compose.yml.tpl index 143d3cec1..89660d419 100644 --- a/infra-templates/vxlan-overlay-network/6/docker-compose.yml.tpl +++ b/infra-templates/vxlan-overlay-network/6/docker-compose.yml.tpl @@ -3,7 +3,7 @@ version: '2' services: vxlan-network: - image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39 + image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.40 command: - /bin/bash - -c @@ -27,7 +27,7 @@ services: max-file: '2' vxlan-router: - image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39 + image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.40 command: start-vxlan.sh cap_add: - NET_ADMIN @@ -44,7 +44,7 @@ services: net.ipv4.conf.default.send_redirects: '0' cni-driver: - image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39 + image: ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.40 command: start-cni-driver.sh privileged: true network_mode: host diff --git a/integration/core/test_catalog.py b/integration/core/test_catalog.py index 2de472350..4a70fa986 100644 --- a/integration/core/test_catalog.py +++ b/integration/core/test_catalog.py @@ -565,7 +565,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): overlay_docker = overlay_files['docker-compose.yml.tpl'] overlay_platform = overlay_files['rancher-compose.yml'] overlay_image = ( - 'ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39') + 'ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.40') assert overlay_docker.count('image: {}'.format(overlay_image)) == 4 assert overlay_docker.count( "PASTURESTACK_FIREWALL_BACKEND: '${FIREWALL_BACKEND}'") == 1 @@ -607,7 +607,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): vxlan_docker = vxlan_files['docker-compose.yml.tpl'] vxlan_platform = vxlan_files['rancher-compose.yml'] alternative_network_image = ( - 'ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39') + 'ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.40') assert vxlan_docker.count( 'image: {}'.format(alternative_network_image)) == 3 assert '\n vxlan-network:\n' in vxlan_docker @@ -632,7 +632,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): layer_2_docker = layer_2_files['docker-compose.yml.tpl'] layer_2_platform = layer_2_files['rancher-compose.yml'] flat_network_image = ( - 'ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.39') + 'ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.40') assert layer_2_docker.count( 'image: {}'.format(flat_network_image)) == 1 assert '\n layer-2-flat-cni:\n' in layer_2_docker @@ -1206,7 +1206,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): 'v0.3.10', 'v0.3.11', [ ( 'ipsec-vxlan-overlay-network:v0.14.38', - 'ipsec-vxlan-overlay-network:v0.14.39', + 'ipsec-vxlan-overlay-network:v0.14.40', ), ], ), @@ -1215,7 +1215,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): 'v0.3.4', 'v0.3.5', [ ( 'ipsec-vxlan-overlay-network:v0.14.37', - 'ipsec-vxlan-overlay-network:v0.14.39', + 'ipsec-vxlan-overlay-network:v0.14.40', ), ], ), @@ -1224,7 +1224,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): 'v0.3.2', 'v0.3.3', [ ( 'ipsec-vxlan-overlay-network:v0.14.34', - 'ipsec-vxlan-overlay-network:v0.14.39', + 'ipsec-vxlan-overlay-network:v0.14.40', ), ], ), @@ -1233,7 +1233,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): 'v0.3.3', 'v0.3.4', [ ( 'ipsec-vxlan-overlay-network:v0.14.34', - 'ipsec-vxlan-overlay-network:v0.14.39', + 'ipsec-vxlan-overlay-network:v0.14.40', ), ], ), From ef9f3d411f09ad030d7ecf8861f8d27e0c7b51bb Mon Sep 17 00:00:00 2001 From: chen21019 <19357113+chen21019@users.noreply.github.com> Date: Fri, 23 Oct 2026 23:06:44 +0800 Subject: [PATCH 08/10] Pin published preloader and align current template documentation --- README.md | 260 +++--------------- SUPPORTED.md | 45 +-- catalog-images.json | 30 +- .../container-schedule/3/README.md | 8 +- .../container-schedule/3/README.zh-TW.md | 8 +- infra-templates/healthcheck/2/README.md | 8 +- infra-templates/healthcheck/2/README.zh-TW.md | 10 +- infra-templates/ipsec-overlay/13/README.md | 23 +- .../ipsec-overlay/13/README.zh-TW.md | 50 +--- .../layer-2-flat-network/7/README.md | 6 +- .../layer-2-flat-network/7/README.zh-TW.md | 6 +- infra-templates/network-services/11/README.md | 4 +- .../network-services/11/README.zh-TW.md | 4 +- .../per-host-subnet-network/5/README.md | 8 +- .../per-host-subnet-network/5/README.zh-TW.md | 8 +- .../resource-scheduler/6/README.md | 2 +- .../resource-scheduler/6/README.zh-TW.md | 2 +- infra-templates/route53-dns-sync/3/README.md | 4 +- .../route53-dns-sync/3/README.zh-TW.md | 4 +- .../secret-volume-driver/3/README.md | 2 +- .../secret-volume-driver/3/README.zh-TW.md | 2 +- .../system-image-preloader/3/README.md | 10 +- .../system-image-preloader/3/README.zh-TW.md | 8 +- .../3/docker-compose.yml.tpl | 2 +- .../3/rancher-compose.yml | 2 +- .../system-image-preloader/config.yml | 2 +- .../vault-volume-driver/4/README.md | 4 +- .../vault-volume-driver/4/README.zh-TW.md | 4 +- .../vxlan-overlay-network/6/README.md | 6 +- .../vxlan-overlay-network/6/README.zh-TW.md | 6 +- integration/core/test_catalog.py | 28 +- 31 files changed, 195 insertions(+), 371 deletions(-) diff --git a/README.md b/README.md index 3eac935fe..371551af5 100644 --- a/README.md +++ b/README.md @@ -8,229 +8,47 @@ PastureStack is an independent community effort to preserve, audit, and moderniz ## Project status -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.14`; 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. - -The current tree is a deliberately small release candidate. It contains only -templates whose image source, semantic version tag, license boundary, and -vulnerability result are recorded in -[catalog-images.json](catalog-images.json). Historical upstream templates and -unreviewed migration work remain available through the preserved Git history, -but they are not exposed as deployable catalog entries. Previously published -PastureStack template versions remain in their original numeric version -directories when an installed system stack can still reference them; the -current reviewed version remains the default. - -The supported set contains the `PastureStack Native` project template and -twenty-one infrastructure entries selected from the preserved upstream -first-party catalog: `PastureStack Container Schedule`, -`PastureStack Amazon ECR Credential Sync`, `PastureStack System Image -Preloader`, `Metadata Healthcheck`, `PastureStack Network Services`, -`PastureStack Network Diagnostics`, `PastureStack Network Policy Manager`, -`PastureStack IPsec Overlay`, -`PastureStack Windows ECR Credential Sync`, -`PastureStack Windows Network Services`, -`PastureStack Windows Container Networking`, -`Resource Scheduler`, `PastureStack Amazon EBS Storage`, -`PastureStack Amazon EFS Storage`, `PastureStack NFS Storage`, -`PastureStack Secret Volume`, `PastureStack Vault Volume`, and -`PastureStack Route 53 DNS Sync`, together -with the alternative -`PastureStack Layer 2 Flat Network`, `PastureStack Per-Host Subnet Network`, -and `PastureStack VXLAN Overlay Network` drivers. General third-party -application examples are intentionally excluded. -The source path and historical upstream status of every enabled -infrastructure entry are recorded in -[catalog-provenance.json](catalog-provenance.json). These provenance records -describe the source tree at the preserved boundary; they do not claim current -vendor certification, endorsement, or support for the PastureStack revisions. -The former Rancher-era Kubernetes entry is no longer deployable from this -catalog. Its Kubernetes 1.12, etcd 2.3, Docker-shim, and Helm 2 contracts cannot -be upgraded by replacing an image tag. The historical templates remain in Git; -new clusters must use a current Kubernetes provisioning path and the separately -maintained `kubernetes-package` component bundle where appropriate. -The three Windows entries restore the official upstream ECR, Metadata/DNS, and -NAT/transparent-networking intents with PastureStack-owned semantic image -tags. Their source tests, Windows cross-compilation, PE inspection, license -files, anonymous distribution, and vulnerability gates passed. No Windows -container host was available for an end-to-end runtime gate, so these entries -remain explicitly identified as release candidates and schedule only to -compatible Windows Server 2022 hosts. -These entries -passed clean project-template provisioning on an isolated VM: the node agent -became active, all four system stacks became healthy, and all six system images -were verified. The network, overlay, and health entries also passed multi-host -managed-network, Metadata, DNS, control-plane return-traffic, firewall, -health-reporting, and encrypted-workload gates. The scheduler passed source, -build, security, public distribution, live Metadata, idempotent reservation, -managed allocation, and restart gates. Version `v0.8.15` additionally remained -healthy through repeated Metadata long-poll windows in production without a -second container start. Network Services version `9` moves to `v0.8.21`, -keeps the host's actual Docker firewall path, and adds deterministic CNI -provider selection, exact immutable-container wrapper binding, symlink-safe -atomic wrapper repair, and a managed-subnet fallback for the short interval -before Metadata reports a new container address. The fallback accepts exactly -one address from the selected running container and revalidates its PID before -installing host-port rules; ambiguity preserves the last known-good rules. -Network Services version `10` (visible version `v0.3.8`) uses the published -Network Plugin Manager `v0.8.22` to converge the legacy `10-rancher.conf` and current -`10-pasturestack.conf` CNI configuration during an infrastructure upgrade. -It changes only the manager image; Metadata Service `v0.9.11`, Internal DNS -`v0.17.11`, firewall choices, questions, sidekicks, and shared volumes retain -version `9`'s contract. The SSH-signed annotated component tag points to source -commit `7b0920aa0c8f3b2c009c9c47c94c4d21b77c7077`; the published manifest and -actual runtime scan evidence are recorded in `catalog-images.json`. Its -official Release run downloaded the vulnerability database at -`2026-10-07T02:47:02Z` and the all-severity runtime and secret gate passed. -This publication evidence does not qualify the managed QA upgrade or rollback. -Version `9` remains immutable and available for installed stacks. -Version `8` introduced the `v0.8.20` forwarding contract that -rejects malformed per-host subnet labels before applying host firewall rules, -and preserves routed container source IPs between validated active peers. It -also restores bounded inbound forwarding for fixed shared overlay subnets, -binds every forwarding rule to the exact configured subnet and managed bridge, -and protects bridge traffic from `route_localnet` loopback routing while -preserving and restoring the operator's original per-bridge setting. Layer 2 -Flat Network version `6` moves to `v0.14.37`. Its Flat IPAM keeps an explicitly -configured host bridge address, but when `bridgeSubnet` is a network prefix it -deterministically selects the first usable address only if that address is -actually present. Ambiguous multi-address bridges still fail closed. -Restored-data provisioning, complete multi-host -scheduler lifecycle, and complete project-template upgrade and rollback remain -release-candidate gates. The two alternative network drivers passed packaged -CNI address allocation and cleanup in isolated Linux network namespaces. -Layer 2 bridge setup and the Per-Host controller's marked routes and dedicated -IP set also passed without changing a production host interface. Per-Host -version `3` uses the control plane's plain-text host-label endpoint. On two -isolated Ubuntu 26.04.1 / Docker 29.8 hosts, the source-equivalent candidate -passed bidirectional workload ping and TCP, service DNS, egress, a published -host port, Docker restart, and both host reboots. The peer was explicitly -tested with native nftables, iptables-nft, and iptables-legacy, then restored -to its pre-test firewall frontend. This does not qualify every -existing deployment's upgrade or rollback path. The -alternative drivers are not installed automatically by the project template. - -Firewall acceptance keeps module ownership intact: Network Plugin Manager -alone manages host NAT, forwarding marks, and host-port `CATTLE_*` chains; -IPsec Overlay manages XFRM and routes without patching those host chains; -Network Policy Manager manages only its own nftables policy table. The bridge -CNI templates pass `hostNat` to Network Plugin Manager and never enable the -CNI binary's separate `ipMasq` host-NAT path. VXLAN's local MASQUERADE rule is -confined to the overlay container's network namespace. Host-chain writers -must follow the host's active Docker backend, including iptables-nft or -iptables-legacy on a new Ubuntu release, and must fail on a mismatch without -silently switching backends; the policy manager's independent nftables table -coexists with all three modes. The three-backend isolated rule tests do not -replace the coupled two-host service, workload egress/DNS, restart, and -rollback gates before the new Catalog versions become deployable. - -IPsec Overlay template version `6` targets `v0.14.31`, retaining version `5`'s -bounded port handoff. It retries a temporarily offline peer through the -existing health reconciliation without restarting the shared charon daemon or -changing Network Plugin Manager's host-firewall ownership. The exact image -digest, security result, and two-host peer-restart evidence are separate -publication gates; earlier template versions remain unchanged. - -IPsec Overlay template version `7` targets `v0.14.32` for the same managed -network contract. A live two-host upgrade exposed two long-lived established -IKE SAs for one peer, so version `7` is retained only for existing stacks and -is not the recommended update. Version `8` targets `v0.14.33`: the IPsec -module alone handles peer-SA recovery and conservative cleanup of an idle -duplicate, while Network Plugin Manager retains sole ownership of host NAT, -forwarding marks, and host ports. The three-backend firewall selection is -unchanged. Version `9` uses `v0.14.34` and corrects the bundled CNI host-label -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. - -IPsec Overlay version `11` and VXLAN Overlay Network version `5` explicitly -declare the fixed shared-subnet ingress contract consumed by Network Plugin -Manager `v0.8.20`. The rule is limited to traffic whose source and destination -are both inside the configured `10.42.0.0/16` subnet and whose output interface -is the exact managed bridge. Overlay routers retain their existing data-plane -responsibilities and do not take ownership of host firewall chains. - -IPsec Overlay version `12` (visible version `v0.3.10`) updates all four service -image references from `v0.14.35` to the publicly verified -[`v0.14.38`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/releases/tag/v0.14.38). -Its signed source commit is `c143e9a5f21ba6df2d1c5002340c71777f875c89` and its -published manifest digest is -`sha256:5b29e08dca8a92fc0ecc7f9d0fdae0457b89daa9d02b1c1c3257bc9dd617c3ae`, -recorded only as verification evidence in `catalog-images.json`. The annotated -Git tag `v0.14.38` is not signed. Version `12` keeps version `11`'s exact -firewall choices, XFRM namespace, sidekick relationships and CNI ownership; -version `11` and its `v0.14.35` inventory are unchanged. Public component -readback verified the linux/amd64 runtime scan with HIGH, CRITICAL and secrets -each zero; it does not establish a zero-CVE or builder-clean claim. This Catalog -candidate still needs its exact-source validation and Catalog API lookup gates. -QA deployment, the complete firewall-mode/plugin matrix, and managed multi-host -upgrade, peer restart and rollback are not claimed by that publication evidence. - -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 -image references. No automatic deployment or publishing trigger is enabled. -The manually dispatched compatibility workflow uses Python `3.14.9`, verifies -every Python dependency against its SHA-256, including the explicitly internal -pip `26.2.2+pasturestack.1` rebuild and official certifi `2026.10.19`. -The frozen shared helper rebuilds official pip source with upstream vendoring, -changing only released urllib3 to `2.8.0`; all inputs, licenses, RECORD hashes, -and the resulting wheel SHA-256 are verified. CI uses an isolated environment, -checks streaming regression and trusted/untrusted TLS behavior, and never -modifies the runner's global Python installation. -It reads back both external and pip-bundled certifi and -runs flake8, pytest, the -Catalog audit, and Catalog Service API gates against the exact selected commit. -GitHub CodeQL independently scans the Actions and Python sources. A Server -release pins the Catalog only after those gates pass; none of these checks is a -production-readiness claim. - -## Resource Scheduler 0.8.20 - -Catalog version `6` selects the published Resource Scheduler `v0.8.20`. -It changes only the image and visible version; questions, credentials, -commands, scheduling labels, and port-80 liveness checks retain version `5`'s -contract. Versions `1` through `5` remain unchanged for installed stacks. -The official release's all-severity runtime scan has 0 High/Critical, -0 vendor-fixed findings, and 0 secrets; 4 Low and 47 Medium vendor-unfixed -findings remain `under_investigation`, not resolved. The published manifest, -source commit, checksum-verified CycloneDX SBOM, and verified GitHub build -provenance are recorded in `catalog-images.json` and the scheduler entry in -`catalog-provenance.json`. - -The component passed reproducible builds, reachable Go vulnerability analysis, -and an isolated packaged-health fixture (non-root port 80, readiness 200, -dependency failure 503, liveness 200, zero restarts). This publication and -Catalog evidence does not qualify a managed-system upgrade or rollback. -Builder-only kernel-header applicability is recorded separately from its raw -findings and does not assess any deployed host kernel. +This source tree provides Catalog `v0.3.14`; its GitHub tag and Release determine +when it is published. It exposes one Native project template and twenty-one +reviewed infrastructure entries. See [SUPPORTED.md](SUPPORTED.md) for the +current versions and [catalog-provenance.json](catalog-provenance.json) for +preserved upstream origins. General third-party application examples and the +obsolete Rancher-era Kubernetes stack are not deployable entries. + +New template revisions consume published PastureStack runtime artifacts built +from verified upstream inputs. Image tags, producer commits, manifest digests, +licenses and runtime evidence are recorded in [catalog-images.json](catalog-images.json). +Deployable Compose definitions use numeric release tags, not digest suffixes. +Available fixes and unreviewed findings block the current security release gate. +Officially unfixed Low/Medium findings remain tracked, not resolved; narrowly +scoped VEX decisions require product-specific evidence and retain the raw scan. +A clean gate is not a claim that every dependency has zero reported CVEs. + +Catalog validation covers template structure, retained versions, Traditional +Chinese labels, exact image references and Catalog Service API lookups. CI uses +Python `3.14.9`, hash-locked dependencies, the explicitly downstream +`pip 26.2.2+pasturestack.1` wheel and official certifi `2026.10.19`. The shared +pip rebuild changes only released urllib3 to `2.8.0`, preserving other vendored +files, licenses and RECORD integrity. Streaming and trusted/untrusted TLS tests +run in an isolated environment, not the runner's global Python installation. + +Published artifacts and successful Catalog checks do not replace environment +acceptance. Verify managed upgrades, rollback and the selected host firewall +backend on isolated hosts before changing an existing installation. Network +Plugin Manager owns host NAT and host-port rules; IPsec owns XFRM and routes; +Network Policy Manager owns only its policy table. Templates do not silently +switch the host's Docker firewall backend. Windows definitions retain their +existing platform restrictions; a Windows-host runtime matrix is not claimed. +No automatic deployment is performed by this repository. ## Version retention contract -A numeric template version becomes immutable after a Server release or a live -stack can reference it. It must not be deleted, renumbered, or silently replaced -when a later version is added. This repository therefore retains every version -still referenced by the reviewed deployment: Metadata Healthcheck `0`; -IPsec Overlay, Network Services, NFS Storage, Resource Scheduler, Network -Diagnostics, Network Policy Manager, and Secret Volume Driver `1`; and each -corresponding current definition. Historical definitions are restored exactly -from reviewed immutable source snapshots; their original commits and contents -remain available in Git history without making prerelease tag names part of the -current operator workflow. Taiwan Traditional Chinese readmes are added without -changing those workload definitions. The integration gate resolves its explicitly -listed retained and current version IDs through Catalog Service, including both -IPsec Overlay `11` and `12`, and Network Services `9` and `10`, so an existing -stack cannot regress to a -version-detail 404. +Published numeric template directories are immutable: do not delete, renumber +or silently replace a revision that a Server release or installed stack can +reference. This release adds new directories and updates defaults while keeping +the previously published definitions unchanged. The integration gate resolves +both retained and current version IDs through Catalog Service so existing +stacks do not regress to a version-detail 404. ## Distribution @@ -262,7 +80,7 @@ Enabled templates may additionally expose user-interface translations through `io.pasturestack.catalog.name.` and `io.pasturestack.catalog.description.` labels. The compatible Web Console selects an exact locale label and falls back to the canonical English -value when a translation is absent. The current twenty-three entries include Taiwan +value when a translation is absent. The current twenty-two entries include Taiwan Traditional Chinese (`zh-tw`) labels. Runtime configuration keys, Compose fields, image names, and third-party content are not translated because doing so would break interoperability or alter upstream material. diff --git a/SUPPORTED.md b/SUPPORTED.md index 55d3d5bd7..65e926ac2 100644 --- a/SUPPORTED.md +++ b/SUPPORTED.md @@ -9,33 +9,40 @@ or out-of-scope templates from being presented as deployable software. | Entry | Type | Version | Image policy | Release state | |---|---|---|---|---| | PastureStack Native | Project template | v0.3.0 | Composes only reviewed, semantic-versioned infrastructure entries | Clean single-host provisioning and restart passed; restored-data validation pending | -| PastureStack Container Schedule | Infrastructure scheduling service | v0.6.0 | Public PastureStack GHCR image with an explicit version tag | Race tests, anonymous distribution, HIGH/CRITICAL scan, and Docker start/stop lifecycle passed | -| PastureStack System Image Preloader | Infrastructure image-cache service | v0.3.0 | Public PastureStack GHCR image with an explicit version tag | Mock compatibility API discovery, real Docker pull/cache lifecycle, anonymous distribution, and HIGH/CRITICAL scan passed | -| PastureStack Amazon ECR Credential Sync | Infrastructure registry service | v3.1.0 | Public PastureStack GHCR image with an explicit version tag | Source tests, anonymous distribution, and credential lifecycle gates passed | -| Metadata Healthcheck | Infrastructure stack | v0.3.16 | Public PastureStack GHCR image with a non-overwritten version tag | Link-local Metadata integration and stdout/stderr routing passed; production rolling upgrade pending | -| PastureStack Network Services | Infrastructure system stack | v0.3.8 candidate | Published Network Plugin Manager v0.8.22; Metadata Service v0.9.11 and Internal DNS v0.17.11 unchanged | Formal component Release and fresh-DB all-severity runtime/secret scan passed; exact-image QA upgrade and rollback remain required; the previous two-host evidence below belongs to v0.8.21 | -| PastureStack Network Diagnostics | Infrastructure diagnostics service | v0.2.1 | Two public PastureStack GHCR images with explicit version tags | Reproducible builds, anonymous distribution, full snapshot and bundle lifecycle, persistence, localization, and HIGH/CRITICAL scan passed | -| PastureStack Network Policy Manager | Infrastructure network-policy agent | v0.3.2 | Public PastureStack GHCR image with an explicit version tag | Five consecutive two-host default-deny, directed TCP allow, rollback, cleanup, and zero-restart gates passed | -| PastureStack IPsec Overlay | Infrastructure network driver | v0.3.2 candidate | v0.14.27 published and manifest digest locked | Isolated VM two-container XFRM and encrypted-packet check passed; formal two-host control-plane lifecycle pending | +| PastureStack Container Schedule | Infrastructure scheduling service | v0.6.1 | Public PastureStack GHCR image with an explicit version tag | Published component; exact runtime evidence is in catalog-images.json; environment upgrade/rollback remains separate | +| PastureStack System Image Preloader | Infrastructure image-cache service | v0.3.2 | Public PastureStack GHCR image with an explicit version tag | Published component; exact runtime evidence is in catalog-images.json; environment upgrade/rollback remains separate | +| PastureStack Amazon ECR Credential Sync | Infrastructure registry service | v3.1.5 | Public PastureStack GHCR image with an explicit version tag | Source tests, anonymous distribution, and credential lifecycle gates passed | +| Metadata Healthcheck | Infrastructure stack | v0.3.17 | Public PastureStack GHCR image with a non-overwritten version tag | Published component; exact runtime evidence is in catalog-images.json; environment upgrade/rollback remains separate | +| PastureStack Network Services | Infrastructure system stack | v0.3.9 | Published Network Plugin Manager v0.8.22; Metadata Service v0.9.11 and Internal DNS v0.17.11 unchanged | Published component; exact runtime evidence is in catalog-images.json; environment upgrade/rollback remains separate | +| PastureStack Network Diagnostics | Infrastructure diagnostics service | v0.2.2 | Two public PastureStack GHCR images with explicit version tags | Published component; exact runtime evidence is in catalog-images.json; environment upgrade/rollback remains separate | +| PastureStack Network Policy Manager | Infrastructure network-policy agent | v0.3.4 | Public PastureStack GHCR image with an explicit version tag | Published component; exact runtime evidence is in catalog-images.json; environment upgrade/rollback remains separate | +| PastureStack IPsec Overlay | Infrastructure network driver | v0.3.11 | v0.14.27 published and manifest digest locked | Published component; exact runtime evidence is in catalog-images.json; environment upgrade/rollback remains separate | | PastureStack Windows ECR Credential Sync | Windows infrastructure registry service | v3.1.2 | Public PastureStack GHCR Windows image with an explicit version tag | Source tests, cross-compilation, PE, license, anonymous distribution, and vulnerability gates passed; Windows-host runtime pending | | PastureStack Windows Network Services | Windows infrastructure Metadata and DNS stack | v0.3.0 | Two public PastureStack GHCR Windows images with explicit version tags | Source tests, cross-compilation, PE, license, anonymous distribution, and vulnerability gates passed; Windows-host runtime pending | -| PastureStack Windows Container Networking | Windows NAT and transparent network-driver definition | v0.1.0 | Reviewed selector-only placeholder image with an explicit version tag | Catalog rendering and compatibility-boundary review passed; Windows-host network-driver lifecycle pending | -| PastureStack Layer 2 Flat Network | Optional infrastructure network driver | v0.3.0 | Reviewed network image with a semantic version tag; bridge setup is opt-in | Packaged Flat CNI ADD/DEL and isolated physical-bridge setup passed | -| Resource Scheduler | Infrastructure scheduling agent | v0.8.19 candidate | Published component v0.8.19, manifest digest and verified SBOM provenance recorded | Formal component release, reproducible builds, all-severity runtime gate, and isolated packaged-health CI passed; these checks do not qualify managed-system upgrade or rollback | -| PastureStack Route 53 DNS Sync | Infrastructure external-DNS agent | v0.8.0 | Public PastureStack GHCR image with an explicit version tag | Route 53 create, update, restart, removal, health, secret, and vulnerability gates passed | -| PastureStack Amazon EBS Storage | Infrastructure block-storage driver | v0.10.0 | Public PastureStack GHCR image with an explicit version tag | Existing-volume contract, safe opt-in provisioning boundary, anonymous distribution, and HIGH/CRITICAL scan passed; live AWS lifecycle pending | -| PastureStack Amazon EFS Storage | Infrastructure shared-storage driver | v0.10.0 | Public PastureStack GHCR image with an explicit version tag | Existing-filesystem contract, controlled mount-target provisioning boundary, anonymous distribution, and HIGH/CRITICAL scan passed; live AWS lifecycle pending | -| PastureStack NFS Storage | Infrastructure storage driver | v0.10.0 | Public PastureStack GHCR image with an explicit version tag | NFS v3 create, mount, read/write, unmount, retain, safe purge, anonymous distribution, and HIGH/CRITICAL scan passed | -| PastureStack Secret Volume | Infrastructure secret-volume driver | v0.1.2 | Public PastureStack GHCR image with an explicit version tag | Production Catalog deployment, authenticated encrypted delivery, non-root `0400` materialization, restart continuity, tmpfs cleanup, anonymous distribution, and HIGH/CRITICAL scan passed | -| PastureStack Vault Volume | Infrastructure Vault token-volume driver | v0.2.1 | Two public PastureStack GHCR images with explicit version tags | Real Vault issue, unwrap, restart recovery, accessor revocation, read-only Secret input, anonymous distribution, and HIGH/CRITICAL scans passed | -| PastureStack Per-Host Subnet Network | Optional infrastructure network driver | v0.3.0 | Reviewed network image with a semantic version tag | Packaged Host-Local CNI ADD/DEL plus isolated route and IP-set reconciliation passed | -| PastureStack VXLAN Overlay Network | Optional infrastructure network driver | v0.3.0 | Reviewed network image with a semantic version tag | Isolated two-node VXLAN forwarding and overlay traffic passed; Catalog lifecycle pending | +| PastureStack Windows Container Networking | Windows NAT and transparent network-driver definition | v0.1.1 | Reviewed selector-only placeholder image with an explicit version tag | Catalog rendering and compatibility-boundary review passed; Windows-host network-driver lifecycle pending | +| PastureStack Layer 2 Flat Network | Optional infrastructure network driver | v0.3.5 | Reviewed network image with a semantic version tag; bridge setup is opt-in | Published component; exact runtime evidence is in catalog-images.json; environment upgrade/rollback remains separate | +| Resource Scheduler | Infrastructure scheduling agent | v0.8.20 | Published component v0.8.19, manifest digest and verified SBOM provenance recorded | Published component; exact runtime evidence is in catalog-images.json; environment upgrade/rollback remains separate | +| PastureStack Route 53 DNS Sync | Infrastructure external-DNS agent | v0.8.1 | Public PastureStack GHCR image with an explicit version tag | Published component; exact runtime evidence is in catalog-images.json; environment upgrade/rollback remains separate | +| PastureStack Amazon EBS Storage | Infrastructure block-storage driver | v0.11.1 | Public PastureStack GHCR image with an explicit version tag | Published component; exact runtime evidence is in catalog-images.json; environment upgrade/rollback remains separate | +| PastureStack Amazon EFS Storage | Infrastructure shared-storage driver | v0.11.1 | Public PastureStack GHCR image with an explicit version tag | Published component; exact runtime evidence is in catalog-images.json; environment upgrade/rollback remains separate | +| PastureStack NFS Storage | Infrastructure storage driver | v0.11.1 | Public PastureStack GHCR image with an explicit version tag | Published component; exact runtime evidence is in catalog-images.json; environment upgrade/rollback remains separate | +| PastureStack Secret Volume | Infrastructure secret-volume driver | v0.1.3 | Public PastureStack GHCR image with an explicit version tag | Published component; exact runtime evidence is in catalog-images.json; environment upgrade/rollback remains separate | +| PastureStack Vault Volume | Infrastructure Vault token-volume driver | v0.2.2 | Two public PastureStack GHCR images with explicit version tags | Published component; exact runtime evidence is in catalog-images.json; environment upgrade/rollback remains separate | +| PastureStack Per-Host Subnet Network | Optional infrastructure network driver | v0.3.3 | Reviewed network image with a semantic version tag | Published component; exact runtime evidence is in catalog-images.json; environment upgrade/rollback remains separate | +| PastureStack VXLAN Overlay Network | Optional infrastructure network driver | v0.3.4 | Reviewed network image with a semantic version tag | Published component; exact runtime evidence is in catalog-images.json; environment upgrade/rollback remains separate | Deployable image references contain semantic version tags only. A published version tag must never be replaced. Manifest digests are retained only in the corresponding GitHub Release verification evidence; they are not placed in Catalog, Compose, API, or user-interface values. +## Historical acceptance evidence + +The sections below preserve earlier environment and feature acceptance context. +They do not claim that those older image versions are the current defaults or +that a new artifact has already passed an environment's upgrade/rollback. The +table above and `catalog-images.json` are the current version and artifact record. + ## PastureStack Native evidence The project template references only the four enabled PastureStack diff --git a/catalog-images.json b/catalog-images.json index 10589a4ce..e608d1138 100644 --- a/catalog-images.json +++ b/catalog-images.json @@ -1193,19 +1193,37 @@ "platforms": [ "linux/amd64" ], - "reference": "ghcr.io/pasturestack/system-image-preloader:v0.3.1", - "sourceCommit": "24e175a679540a99ee93696338affeee7c2d332b", - "manifestDigest": "sha256:09e9ad1e70546aacb87ef843e39cd31aff9463ca04a0ada70654f153f07930b9", + "reference": "ghcr.io/pasturestack/system-image-preloader:v0.3.2", + "sourceCommit": "bcd89e7fb6baafea381de380c256e4e8d62f1df2", + "manifestDigest": "sha256:a8468db6579e8a49f2e56218c3010ac775e3b56a0f188e53a01f4002fe45b9b3", "reviewedAt": "2026-10-23", "vulnerabilityScan": { - "scope": "published runtime image", + "scope": "published runtime image, full severity and exact OpenVEX", "high": 0, "critical": 0, - "evidence": "https://github.com/PastureStack/system-image-preloader/actions/runs/39958486019" + "evidence": "https://github.com/PastureStack/system-image-preloader/actions/runs/39973323966", + "low": 4, + "medium": 57, + "unknown": 0, + "secrets": 0, + "fixedAvailable": 0, + "actionable": 0, + "rawFindings": 62, + "effectiveFindings": 61, + "vendorUnfixedLowMedium": 61, + "disposition": "under_investigation", + "reportSha256": "e943e42f8b2c690659b20c8637f0d73bb4f1f500cc39be5201dbe80d35c18428", + "effectiveReportSha256": "42813d711ceb797d8e42ff8de76d10c40607e28e52df2159bac09ee4d5341f0e", + "openVexSha256": "d5b93f4d9b549805cde16dc077d26ac74c568eae9afa305bfa9d58dd37988761" }, "publicationVerification": { "source": "component owner verified anonymous manifest/config readback", - "workflowRun": "https://github.com/PastureStack/system-image-preloader/actions/runs/39958486019" + "workflowRun": "https://github.com/PastureStack/system-image-preloader/actions/runs/39973323966" + }, + "sbom": { + "format": "CycloneDX", + "url": "https://github.com/PastureStack/system-image-preloader/releases/download/v0.3.2/system-image-preloader-sbom.cdx.json", + "sha256": "43edb541dd9e4c86d78435645798361aad89be579ce7fad8accca608bc6c0b7b" } }, { diff --git a/infra-templates/container-schedule/3/README.md b/infra-templates/container-schedule/3/README.md index dcb948da5..3cdc92d57 100644 --- a/infra-templates/container-schedule/3/README.md +++ b/infra-templates/container-schedule/3/README.md @@ -1,6 +1,6 @@ -# PastureStack Container Schedule v0.6.0 +# PastureStack Container Schedule v0.6.1 This infrastructure service watches Docker container events and runs scheduled `start`, `stop`, or `restart` actions. A managed workload opts in with these @@ -13,8 +13,8 @@ labels: ## Reviewed image -- Image: `ghcr.io/pasturestack/container-cron:v0.6.0` -- Source: [`PastureStack/container-cron@8645472791ebbc9f78628af716e061139554fb38`](https://github.com/PastureStack/container-cron/tree/8645472791ebbc9f78628af716e061139554fb38) +- Image: `ghcr.io/pasturestack/container-cron:v0.6.1` +- Source: [`PastureStack/container-cron@2cce2cc80f2590239d5ef758a21c54a3f1e0f2b9`](https://github.com/PastureStack/container-cron/tree/2cce2cc80f2590239d5ef758a21c54a3f1e0f2b9) - Source license: Apache-2.0; Ubuntu and bundled Go dependencies retain their upstream licenses - Security gate: Trivy HIGH 0 and CRITICAL 0 for the operating system and Go @@ -38,7 +38,7 @@ protocol identifiers, not PastureStack branding. The release passed race-enabled unit tests, static analysis, image metadata and license checks, a current HIGH/CRITICAL vulnerability scan, and an isolated -Docker 29.4 lifecycle test. The test created one stopped workload and one +Docker lifecycle test. The test created one stopped workload and one running workload, then verified that the service started the first and stopped the second on schedule. All test containers were removed afterward. diff --git a/infra-templates/container-schedule/3/README.zh-TW.md b/infra-templates/container-schedule/3/README.zh-TW.md index f5ffb943a..5c75132bd 100644 --- a/infra-templates/container-schedule/3/README.zh-TW.md +++ b/infra-templates/container-schedule/3/README.zh-TW.md @@ -1,6 +1,6 @@ -# PastureStack 容器定時排程 v0.6.0 +# PastureStack 容器定時排程 v0.6.1 此基礎架構服務會監看 Docker 容器事件,並依排程執行 `start`、 `stop` 或 `restart`。受管工作負載可使用下列標籤啟用排程: @@ -12,9 +12,9 @@ ## 已審核映像 -- 映像:`ghcr.io/pasturestack/container-cron:v0.6.0` +- 映像:`ghcr.io/pasturestack/container-cron:v0.6.1` - 原始碼: - [`PastureStack/container-cron@8645472791ebbc9f78628af716e061139554fb38`](https://github.com/PastureStack/container-cron/tree/8645472791ebbc9f78628af716e061139554fb38) + [`PastureStack/container-cron@2cce2cc80f2590239d5ef758a21c54a3f1e0f2b9`](https://github.com/PastureStack/container-cron/tree/2cce2cc80f2590239d5ef758a21c54a3f1e0f2b9) - 原始碼採 Apache-2.0 授權;Ubuntu 與內含的 Go 相依套件保留各自的 上游授權。 - Trivy 掃描結果為 HIGH 0、CRITICAL 0。 @@ -34,7 +34,7 @@ Docker Socket 權限等同主機管理者權限,因此只能將此範本當成 ## 驗證 此版本已通過啟用競爭偵測的單元測試、靜態分析、映像中繼資料與授權 -檢查、弱點掃描,以及 Docker 29.4 隔離環境生命週期測試。測試確認 +檢查、弱點掃描,以及 Docker 隔離環境生命週期測試。測試確認 服務能依排程啟動一個已停止的工作負載,並停止另一個執行中的工作負載; 測試資源已精確移除。 diff --git a/infra-templates/healthcheck/2/README.md b/infra-templates/healthcheck/2/README.md index 14a22e7d7..6254b674c 100644 --- a/infra-templates/healthcheck/2/README.md +++ b/infra-templates/healthcheck/2/README.md @@ -1,13 +1,13 @@ -# Metadata Healthcheck v0.3.16 +# Metadata Healthcheck v0.3.17 This infrastructure stack runs one healthcheck agent on every eligible host. The agent reads health declarations from the established link-local Metadata endpoint, manages its private HAProxy process, and reports stable state changes to the compatible control API. ## Reviewed image -- Image: `ghcr.io/pasturestack/metadata-healthcheck:v0.3.16` -- Source: [`PastureStack/metadata-healthcheck@df38ca1c4712ba4919c73fb329d87a1940b6970f`](https://github.com/PastureStack/metadata-healthcheck/tree/df38ca1c4712ba4919c73fb329d87a1940b6970f) +- Image: `ghcr.io/pasturestack/metadata-healthcheck:v0.3.17` +- Source: [`PastureStack/metadata-healthcheck@410993d3b3b2493bbd84a36f7d67cfefb8dd6705`](https://github.com/PastureStack/metadata-healthcheck/tree/410993d3b3b2493bbd84a36f7d67cfefb8dd6705) - Source license: Apache-2.0; bundled operating-system packages retain their upstream licenses - Security gate: Trivy HIGH 0, CRITICAL 0, image secrets 0, and source secrets 0 - Distribution gate: public GHCR and unauthenticated version-tag pull passed @@ -20,4 +20,4 @@ The compatible control plane requires the literal `rancher-compose.yml` filename ## Release boundary -The image-level integration gate passed with the default link-local address, without a neutral Metadata DNS alias, and with routine lifecycle messages on standard output while actual failures remain on standard error. Earlier Catalog-created deployments verified credential injection, compatibility mapping, global scheduling, readiness, restart, two-daemon reporting, and removal. The stack remains a release candidate until v0.3.16 passes a fresh multi-host upgrade, rollback, and complete infrastructure-stack removal on isolated VM snapshots. Do not use this template to modify an existing production control plane. +The image-level integration gate passed with the default link-local address, without a neutral Metadata DNS alias, and with routine lifecycle messages on standard output while actual failures remain on standard error. Earlier Catalog-created deployments verified credential injection, compatibility mapping, global scheduling, readiness, restart, two-daemon reporting, and removal. Managed multi-host upgrade, rollback, and complete infrastructure-stack removal remain separate deployment acceptance checks. Do not use this template to modify an existing production control plane. diff --git a/infra-templates/healthcheck/2/README.zh-TW.md b/infra-templates/healthcheck/2/README.zh-TW.md index 476627e0b..a562d62bd 100644 --- a/infra-templates/healthcheck/2/README.zh-TW.md +++ b/infra-templates/healthcheck/2/README.zh-TW.md @@ -1,6 +1,6 @@ -# 中繼資料健康檢查 v0.3.16 +# 中繼資料健康檢查 v0.3.17 此基礎架構堆疊會在每台符合條件的主機上執行一個健康檢查代理程式。 代理程式從既有的連結本機中繼資料端點讀取健康狀態宣告、管理自己的 @@ -8,9 +8,9 @@ HAProxy 處理程序,並把穩定的狀態變更回報給相容控制 API。 ## 已審核映像 -- 映像:`ghcr.io/pasturestack/metadata-healthcheck:v0.3.16` +- 映像:`ghcr.io/pasturestack/metadata-healthcheck:v0.3.17` - 原始碼: - [`PastureStack/metadata-healthcheck@df38ca1c4712ba4919c73fb329d87a1940b6970f`](https://github.com/PastureStack/metadata-healthcheck/tree/df38ca1c4712ba4919c73fb329d87a1940b6970f) + [`PastureStack/metadata-healthcheck@410993d3b3b2493bbd84a36f7d67cfefb8dd6705`](https://github.com/PastureStack/metadata-healthcheck/tree/410993d3b3b2493bbd84a36f7d67cfefb8dd6705) - 原始碼採 Apache-2.0 授權;作業系統套件保留各自的上游授權。 - Trivy 結果為 HIGH 0、CRITICAL 0,映像及原始碼的機密資料掃描均為 0。 - 公開 GHCR 與未登入拉取版本標籤的驗證已通過。 @@ -32,6 +32,6 @@ Socket、不要求特權模式,也不新增 Linux Capability。 中繼資料 DNS 別名;一般生命週期訊息會寫入標準輸出,只有實際失敗 才會寫入標準錯誤。較早的商店部署也驗證過登入資訊注入、相容名稱 映射、全域排程、就緒狀態、重新啟動、雙常駐程式回報及移除流程。 -在 v0.3.16 於隔離 VM 快照完成新的多主機升級、回復及完整基礎架構 -堆疊移除測試前,此範本仍屬候選版本。請勿使用此範本直接變更既有的 +多主機升級、回復及完整基礎架構堆疊移除仍須在隔離 VM 快照完成 +部署驗收。請勿使用此範本直接變更既有的 正式控制平面。 diff --git a/infra-templates/ipsec-overlay/13/README.md b/infra-templates/ipsec-overlay/13/README.md index bb64c0c1a..b524c93b4 100644 --- a/infra-templates/ipsec-overlay/13/README.md +++ b/infra-templates/ipsec-overlay/13/README.md @@ -1,19 +1,16 @@ -# PastureStack IPsec Overlay 0.3.10 +# PastureStack IPsec Overlay 0.3.11 -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. +This infrastructure template deploys 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 +## Published image -- Image: [`ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.38`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/releases/tag/v0.14.38) was publicly verified on 2026-10-05. Its manifest digest is `sha256:5b29e08dca8a92fc0ecc7f9d0fdae0457b89daa9d02b1c1c3257bc9dd617c3ae`, recorded only as verification evidence in `catalog-images.json`. -- Source: [`c143e9a5f21ba6df2d1c5002340c71777f875c89`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/c143e9a5f21ba6df2d1c5002340c71777f875c89), with a verified commit signature. The annotated Git tag `v0.14.38` is not signed. -- Version `12` updates all four services to the published `v0.14.38` image. It retains version `11`'s namespace, sidekick, XFRM, firewall-selection and CNI-ownership contracts unchanged. Version `11` and its original `v0.14.35` inventory remain available for existing stacks. -- Version `11` explicitly declares `allowSharedSubnetIngress: true` for the fixed `10.42.0.0/16` CNI network. Network Plugin Manager `v0.8.20` uses that contract to restore cross-host workload forwarding without granting traffic outside the configured subnet or managed bridge. Version `10` remains available for existing stacks. -- 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/` 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. +- Image: [`ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.40`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/releases/tag/v0.14.40). +- Source: [`4711833178a05e5d225e364cce856bd108bdc707`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/4711833178a05e5d225e364cce856bd108bdc707), with a verified signed tag. +- Revision 13 preserves revision 12's namespaces, sidekicks, XFRM, firewall selection and CNI ownership. Existing numeric revisions remain unchanged. +- The full runtime scan has no available fix, High/Critical finding, unknown severity or secret. The 54 officially unfixed Low/Medium findings remain tracked, not resolved; the SBOM, digest and report are recorded in `catalog-images.json`. +- Source license: Apache-2.0; bundled dependencies retain their upstream licenses and notices. ## Privilege and secret boundary @@ -31,6 +28,6 @@ The host firewall backend is selected explicitly or left at `auto`. The four sup 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 +## Deployment boundary -Public readback verified the `v0.14.38` image manifest and config, version and source labels, and its linux/amd64 runtime scan with HIGH, CRITICAL and secrets each zero. This runtime-only result is not a zero-CVE or builder-clean claim. Catalog version `12` is still a candidate: its exact-source Catalog validation and API version lookup remain separate gates. No QA deployment or complete firewall-mode/plugin matrix is claimed. Isolated native nftables, iptables-nft and iptables-legacy checks, managed upgrade, peer restart and rollback must be accepted separately; a successful CNI address allocation alone does not prove the encrypted multi-host lifecycle. +Published runtime and Catalog validation are separate from managed deployment acceptance. Verify the selected firewall backend, peer restart, upgrade and rollback on isolated hosts before applying the stack to an existing environment. A successful CNI address allocation alone does not prove the encrypted multi-host lifecycle. diff --git a/infra-templates/ipsec-overlay/13/README.zh-TW.md b/infra-templates/ipsec-overlay/13/README.zh-TW.md index c68ed3534..d70374da9 100644 --- a/infra-templates/ipsec-overlay/13/README.zh-TW.md +++ b/infra-templates/ipsec-overlay/13/README.zh-TW.md @@ -1,40 +1,19 @@ -# PastureStack IPsec 加密網路 0.3.10 +# PastureStack IPsec 加密網路 0.3.11 -此候選基礎架構範本預計在每台符合條件的主機上安裝 IPsec 加密 +此基礎架構範本會在每台符合條件的主機上安裝 IPsec 加密 網路資料平面。網路持有服務負責受管命名空間;路由器套用主機 XFRM 與路由狀態;連線檢查相關容器提供控制平面健康狀態契約;CNI 相關 容器則提供網橋與位址管理執行檔。 -## 候選範本:映像已發布 +## 正式發布映像 -- [映像 `ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.38`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/releases/tag/v0.14.38) - 已於 2026-10-05 完成公開發布讀回。真實 manifest digest 為 - `sha256:5b29e08dca8a92fc0ecc7f9d0fdae0457b89daa9d02b1c1c3257bc9dd617c3ae`, - 僅作為 `catalog-images.json` 中的驗證證據,不加入部署映像引用。 -- [來源 `c143e9a5f21ba6df2d1c5002340c71777f875c89`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/c143e9a5f21ba6df2d1c5002340c71777f875c89) - 的 commit 簽章已驗證;Git tag `v0.14.38` 為 annotated tag,但未簽章。 -- 第 `12` 版將四個服務更新至已發布的 `v0.14.38` 映像,完整保留 - 第 `11` 版的命名空間、相關容器、XFRM、防火牆選擇與 CNI 責任契約。 - 第 `11` 版及其原有 `v0.14.35` inventory 仍供既有堆疊使用。 -- 第 `11` 版為固定的 `10.42.0.0/16` CNI 網路明確設定 - `allowSharedSubnetIngress: true`。網路外掛管理器 `v0.8.20` 依此契約 - 恢復跨主機工作負載轉送,且不放行設定子網路或受管網橋以外的流量。 - 第 `10` 版仍供既有堆疊使用。 -- 第 `10` 版在滾動升級時,若舊版連線檢查容器尚占用 TCP 80, - 新版只對此埠占用情況等待,最多 90 秒;其他監聽錯誤或逾時仍會 - 明確失敗。此處不更動防火牆規則或路由器的 8111 連接埠責任。 - 第 `9` 版仍供既有堆疊使用。 -- 第 `8` 版保留對等主機重試與 8111 連接埠交接。IPsec 模組統一負責 - 缺失 SA 的重建;超過觀察期間且同一對等主機恰有一條已使用的健康 - SA 時,才清除另一條零流量的重複 SA。無法明確判斷的連線不動。 - 第 `7` 版仍供既有堆疊參照,但真機滾動升級後曾留下兩條已建立 SA。 -- 第 `9` 版將隨附 CNI 的主機標籤查詢改為控制平面實際提供的純文字 - `/self/host/labels/` 契約,讓每主機子網路可正確取得網橋與 IPAM - 位址範圍。第 `8` 版仍供既有堆疊使用。 -- 原始碼採 Apache-2.0 授權;Ubuntu、strongSwan、CNI、Weave 與 - 隨附相依套件保留各自的上游授權及聲明。 +- [映像 `ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.40`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/releases/tag/v0.14.40)。 +- [來源 `4711833178a05e5d225e364cce856bd108bdc707`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/4711833178a05e5d225e364cce856bd108bdc707),簽署版本標籤已驗證。 +- 第 13 版保留第 12 版的命名空間、相關容器、XFRM、防火牆選擇與 CNI 責任;既有數字版目錄內容不變。 +- 完整執行映像掃描沒有可用修補、High/Critical、未知嚴重度或機密資料;54 筆官方尚無修補的 Low/Medium 持續追蹤,不視為已解決。SBOM、摘要與報告記錄於 `catalog-images.json`。 +- 原始碼採 Apache-2.0 授權;隨附相依套件保留各自的上游授權及聲明。 ## 權限與機密資料界線 @@ -81,15 +60,6 @@ Native 專案定義將 Network Services 排在 IPsec 前面,但清單順序 防火牆後端、`bridge-accept-fwmark` 與持久 IPv4 轉送前置設定; 只有 IPsec 路由器無法提供管理器負責的轉送及 NAT 規則。 -## 發布界線 +## 部署界線 -公開讀回已確認 `v0.14.38` 映像的 manifest、config、版本與來源標籤, -以及 linux/amd64 執行映像掃描的 HIGH、CRITICAL 與 secrets 均為零。 -這只代表執行映像的結果,不是零 CVE 或建置映像無風險的宣告。 -第 `12` 版 Catalog 範本仍為候選;精確來源的 Catalog 驗證及 API -版本查詢是分開的驗收關卡,尚未宣告 QA 部署或完整防火牆模式/外掛矩陣通過。 -原生 nftables、iptables-nft 與 iptables-legacy 的隔離檢查、受管升級、 -對等主機重啟及回復須另行驗收。仍須確認暫時離線的主機不拆掉其他 -健康連線、同一對等主機收斂為一條可用 IKE SA、新路由器等待 8111 -埠釋放,且不越界修改網路外掛管理器的防火牆規則。 -單純完成 CNI 位址分配不能代替加密跨主機生命週期驗收。 +正式執行映像與 Catalog 驗證不同於受管部署驗收。套用既有環境前,須於隔離主機驗證所選防火牆後端、對端重啟、升級及回復。單純完成 CNI 位址分配不能代替加密跨主機生命週期驗收。 diff --git a/infra-templates/layer-2-flat-network/7/README.md b/infra-templates/layer-2-flat-network/7/README.md index 317628d88..4babda68d 100644 --- a/infra-templates/layer-2-flat-network/7/README.md +++ b/infra-templates/layer-2-flat-network/7/README.md @@ -11,11 +11,11 @@ or gateway is wrong. Prepare the bridge through the operating system first, or verify out-of-band console access before enabling automatic setup. The template uses -`ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.37`, which contains the +`ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.40`, which contains the reviewed `pasture-bridge` and `flat-cni-ipam` executables. The image source is -[`PastureStack/ipsec-vxlan-overlay-network@20eb898da1b24ed3b8ab2c0ad212d6523adeddeb`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/20eb898da1b24ed3b8ab2c0ad212d6523adeddeb); +[`PastureStack/ipsec-vxlan-overlay-network@4711833178a05e5d225e364cce856bd108bdc707`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/4711833178a05e5d225e364cce856bd108bdc707); the Flat CNI IPAM source is -[`PastureStack/flat-cni-ipam@4676b320a03fec53ae68899fdf18c7e7f7340356`](https://github.com/PastureStack/flat-cni-ipam/tree/4676b320a03fec53ae68899fdf18c7e7f7340356). +[`PastureStack/flat-cni-ipam@v0.1.6`](https://github.com/PastureStack/flat-cni-ipam/releases/tag/v0.1.6). The template files and icon are MIT licensed. The runtime projects are Apache-2.0; operating-system packages and bundled components retain their own diff --git a/infra-templates/layer-2-flat-network/7/README.zh-TW.md b/infra-templates/layer-2-flat-network/7/README.zh-TW.md index 648b36c4f..f9a883c39 100644 --- a/infra-templates/layer-2-flat-network/7/README.zh-TW.md +++ b/infra-templates/layer-2-flat-network/7/README.zh-TW.md @@ -9,12 +9,12 @@ 若要啟用自動設定,請先確認具備頻外主控台存取方式。 此範本使用 -`ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.37`, +`ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.40`, 其中包含經審核的 `pasture-bridge` 與 `flat-cni-ipam` 執行檔。 映像原始碼位於 -[`PastureStack/ipsec-vxlan-overlay-network@20eb898da1b24ed3b8ab2c0ad212d6523adeddeb`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/20eb898da1b24ed3b8ab2c0ad212d6523adeddeb), +[`PastureStack/ipsec-vxlan-overlay-network@4711833178a05e5d225e364cce856bd108bdc707`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/4711833178a05e5d225e364cce856bd108bdc707), Flat CNI IPAM 原始碼位於 -[`PastureStack/flat-cni-ipam@4676b320a03fec53ae68899fdf18c7e7f7340356`](https://github.com/PastureStack/flat-cni-ipam/tree/4676b320a03fec53ae68899fdf18c7e7f7340356)。 +[`PastureStack/flat-cni-ipam@v0.1.6`](https://github.com/PastureStack/flat-cni-ipam/releases/tag/v0.1.6)。 範本檔案與圖示採 MIT 授權;執行專案採 Apache-2.0 授權。作業系統 套件及隨附元件保留各自的上游授權及聲明。 diff --git a/infra-templates/network-services/11/README.md b/infra-templates/network-services/11/README.md index b84eff7c1..f11e8eac8 100644 --- a/infra-templates/network-services/11/README.md +++ b/infra-templates/network-services/11/README.md @@ -2,7 +2,7 @@ # PastureStack Network Services -Version 10 (visible version `v0.3.8`) uses the published Network Plugin Manager `v0.8.22` for CNI configuration convergence during an upgrade from the historical runtime. It retains single-backend selection, Metadata Service `v0.9.11`, Internal DNS `v0.17.11`, all Catalog questions, and version 9's forwarding and host-port contracts. Version 9 remains immutable. The image's official release provenance, manifest digest, and actual runtime scan evidence are recorded in `catalog-images.json`. +Version 11 (visible version `v0.3.9`) uses the published Network Plugin Manager `v0.8.23`, Metadata Service `v0.10.5`, and Internal DNS `v0.17.13`. This dependency update retains version 10's firewall ownership, CNI convergence, Catalog questions, sidekicks and shared volumes. Earlier numeric revisions remain unchanged. Published source, image digests and runtime scan evidence are recorded in `catalog-images.json`. ## CNI configuration convergence @@ -10,7 +10,7 @@ The manager preflights all desired CNI configurations and writes each through an Retirement renames the obsolete file with a `.pasturestack-retired` suffix, preserving its original bytes outside the CNI `.conf` / `.json` execution set. An existing retirement backup must be byte-identical; a conflicting backup causes an error. Unrelated administrator configurations are preserved. Malformed or partially matching platform configurations, symlinks, and unsafe metadata paths cause an explicit error. The manager never sweeps the configuration directory or removes CNI binary aliases as part of this migration. -The official `v0.8.22` Release passed its all-severity runtime and secret gate with Trivy `0.74.0` after downloading the vulnerability database at `2026-10-07T02:47:02Z`. The published image and its SBOM both identify source commit `7b0920aa0c8f3b2c009c9c47c94c4d21b77c7077`. This revision still requires an exact-image managed upgrade check; component publication does not establish that an existing infrastructure stack has completed its upgrade. +Each component is a published security rebuild. Full-severity evidence is recorded separately from deployment acceptance; publication does not establish that an existing infrastructure stack has completed its managed upgrade. ## Provider and lifecycle convergence diff --git a/infra-templates/network-services/11/README.zh-TW.md b/infra-templates/network-services/11/README.zh-TW.md index cce067738..a1d8487a2 100644 --- a/infra-templates/network-services/11/README.zh-TW.md +++ b/infra-templates/network-services/11/README.zh-TW.md @@ -2,7 +2,7 @@ # PastureStack 網路服務 -第 10 版(顯示版本 `v0.3.8`)使用已正式發布的網路外掛管理器 `v0.8.22`,修正從歷史執行環境升級時的 CNI 設定收斂。單一防火牆後端的選擇方式、中繼資料服務 `v0.9.11`、內部 DNS `v0.17.11`、所有 Catalog 問題,以及第 9 版的轉送與主機連接埠契約均維持原樣;第 9 版保留不可變的原始內容。官方映像來源、manifest digest 與實際執行環境掃描證據記錄於 `catalog-images.json`。 +第 11 版(顯示版本 `v0.3.9`)使用已正式發布的網路外掛管理器 `v0.8.23`、中繼資料服務 `v0.10.5` 與內部 DNS `v0.17.13`。此次相依套件更新保留第 10 版的防火牆責任、CNI 收斂、Catalog 問題、相關容器與共用磁碟區;較早數字版目錄內容不變。正式來源、映像摘要及執行環境掃描證據記錄於 `catalog-images.json`。 ## CNI 設定收斂 @@ -10,7 +10,7 @@ 退役時會將舊檔更名為加上 `.pasturestack-retired` 後綴的備份,保留原始位元組,並移出 CNI `.conf` / `.json` 執行集合。若備份已存在,其內容必須完全一致;內容衝突則明確報錯。管理者的其他設定會保留;格式損壞、只符合部分平台身分、符號連結及不安全的中繼資料路徑都會明確報錯。此次遷移不會掃除整個設定目錄,也不會移除 CNI 執行檔別名。 -官方 `v0.8.22` Release 在 `2026-10-07T02:47:02Z` 下載弱點資料庫後,以 Trivy `0.74.0` 通過全嚴重程度的執行環境弱點與機密資料掃描。發布映像與 SBOM 均指向來源 commit `7b0920aa0c8f3b2c009c9c47c94c4d21b77c7077`。此版本仍須以正式映像完成受管升級驗收;元件發布並不代表既有基礎架構堆疊已完成升級。 +各元件均為正式發布的安全重建。完整嚴重度證據與部署驗收分開記錄;元件發布不代表既有基礎架構堆疊已完成受管升級。 ## Provider 與生命週期收斂 diff --git a/infra-templates/per-host-subnet-network/5/README.md b/infra-templates/per-host-subnet-network/5/README.md index c5533bac5..092bb631f 100644 --- a/infra-templates/per-host-subnet-network/5/README.md +++ b/infra-templates/per-host-subnet-network/5/README.md @@ -16,12 +16,12 @@ bounds use does not advertise the address that other hosts can route through. The template uses -`ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.34`. The image source is -[`PastureStack/ipsec-vxlan-overlay-network@db5a506346f521c6947b21a1a60cef6dd546f983`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/db5a506346f521c6947b21a1a60cef6dd546f983); +`ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.40`. The image source is +[`PastureStack/ipsec-vxlan-overlay-network@4711833178a05e5d225e364cce856bd108bdc707`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/4711833178a05e5d225e364cce856bd108bdc707); the bundled controller is from -[`PastureStack/per-host-subnet@babe7d7f2b7f67a18883b9ed99d17483c8854315`](https://github.com/PastureStack/per-host-subnet/tree/babe7d7f2b7f67a18883b9ed99d17483c8854315), +[`PastureStack/per-host-subnet@v0.2.5`](https://github.com/PastureStack/per-host-subnet/releases/tag/v0.2.5), and the bundled IPAM executable is from -[`PastureStack/host-local-cni-ipam@e79e1721f78a9579145cd89d8ad5083ae24633f5`](https://github.com/PastureStack/host-local-cni-ipam/tree/e79e1721f78a9579145cd89d8ad5083ae24633f5). +[`PastureStack/host-local-cni-ipam@v0.1.6`](https://github.com/PastureStack/host-local-cni-ipam/releases/tag/v0.1.6). The template files and icon are MIT licensed. The runtime projects are Apache-2.0; operating-system packages and bundled components retain their own diff --git a/infra-templates/per-host-subnet-network/5/README.zh-TW.md b/infra-templates/per-host-subnet-network/5/README.zh-TW.md index 86218f1aa..a10ad21cc 100644 --- a/infra-templates/per-host-subnet-network/5/README.zh-TW.md +++ b/infra-templates/per-host-subnet-network/5/README.zh-TW.md @@ -15,13 +15,13 @@ io.pasturestack.network.per-host-subnet.subnet=10.50.1.0/24 `io.pasturestack.network.per-host-subnet.override-agent-ip`。 此範本使用 -`ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.34`。 +`ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.40`。 映像原始碼位於 -[`PastureStack/ipsec-vxlan-overlay-network@db5a506346f521c6947b21a1a60cef6dd546f983`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/db5a506346f521c6947b21a1a60cef6dd546f983), +[`PastureStack/ipsec-vxlan-overlay-network@4711833178a05e5d225e364cce856bd108bdc707`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/4711833178a05e5d225e364cce856bd108bdc707), 隨附控制器來自 -[`PastureStack/per-host-subnet@babe7d7f2b7f67a18883b9ed99d17483c8854315`](https://github.com/PastureStack/per-host-subnet/tree/babe7d7f2b7f67a18883b9ed99d17483c8854315), +[`PastureStack/per-host-subnet@v0.2.5`](https://github.com/PastureStack/per-host-subnet/releases/tag/v0.2.5), 隨附 IPAM 執行檔來自 -[`PastureStack/host-local-cni-ipam@e79e1721f78a9579145cd89d8ad5083ae24633f5`](https://github.com/PastureStack/host-local-cni-ipam/tree/e79e1721f78a9579145cd89d8ad5083ae24633f5)。 +[`PastureStack/host-local-cni-ipam@v0.1.6`](https://github.com/PastureStack/host-local-cni-ipam/releases/tag/v0.1.6)。 範本檔案與圖示採 MIT 授權;執行專案採 Apache-2.0 授權。作業系統 套件及隨附元件保留各自的上游授權及聲明。 diff --git a/infra-templates/resource-scheduler/6/README.md b/infra-templates/resource-scheduler/6/README.md index 76f1b5dd6..c3f654daf 100644 --- a/infra-templates/resource-scheduler/6/README.md +++ b/infra-templates/resource-scheduler/6/README.md @@ -1,6 +1,6 @@ -# Resource Scheduler v0.8.19 +# Resource Scheduler v0.8.20 This template deploys the functional PastureStack resource scheduler as the control plane's scheduling agent. It consumes the established control-plane diff --git a/infra-templates/resource-scheduler/6/README.zh-TW.md b/infra-templates/resource-scheduler/6/README.zh-TW.md index cb1bfeb82..0396962c8 100644 --- a/infra-templates/resource-scheduler/6/README.zh-TW.md +++ b/infra-templates/resource-scheduler/6/README.zh-TW.md @@ -1,6 +1,6 @@ -# 資源排程器 v0.8.19 +# 資源排程器 v0.8.20 此範本會把可正常運作的 PastureStack 資源排程器部署成控制平面的 排程代理程式。排程器使用既有的控制平面事件及中繼資料契約,同時採用 diff --git a/infra-templates/route53-dns-sync/3/README.md b/infra-templates/route53-dns-sync/3/README.md index 02128fc82..c3e30f573 100644 --- a/infra-templates/route53-dns-sync/3/README.md +++ b/infra-templates/route53-dns-sync/3/README.md @@ -5,8 +5,8 @@ This infrastructure template synchronizes service addresses from one compatible environment to an existing Amazon Route 53 hosted zone. -- Image: `ghcr.io/pasturestack/external-dns-sync:v0.8.0` -- Source: [`PastureStack/external-dns-sync@v0.8.0`](https://github.com/PastureStack/external-dns-sync/tree/v0.8.0) +- Image: `ghcr.io/pasturestack/external-dns-sync:v0.8.1` +- Source: [`PastureStack/external-dns-sync@v0.8.1`](https://github.com/PastureStack/external-dns-sync/tree/v0.8.1) - Upstream: [`rancher-archives/external-dns`](https://github.com/rancher-archives/external-dns) The image reference always uses the semantic release tag. Published Catalog diff --git a/infra-templates/route53-dns-sync/3/README.zh-TW.md b/infra-templates/route53-dns-sync/3/README.zh-TW.md index 8c8b6090a..edda164a5 100644 --- a/infra-templates/route53-dns-sync/3/README.zh-TW.md +++ b/infra-templates/route53-dns-sync/3/README.zh-TW.md @@ -6,9 +6,9 @@ 此基礎架構範本會把相容環境的服務位址同步到既有的 Amazon Route 53 託管區域。 -- 映像:`ghcr.io/pasturestack/external-dns-sync:v0.8.0` +- 映像:`ghcr.io/pasturestack/external-dns-sync:v0.8.1` - 原始碼: - [`PastureStack/external-dns-sync@v0.8.0`](https://github.com/PastureStack/external-dns-sync/tree/v0.8.0) + [`PastureStack/external-dns-sync@v0.8.1`](https://github.com/PastureStack/external-dns-sync/tree/v0.8.1) - 上游: [`rancher-archives/external-dns`](https://github.com/rancher-archives/external-dns) diff --git a/infra-templates/secret-volume-driver/3/README.md b/infra-templates/secret-volume-driver/3/README.md index 0e48aa6ef..7fc161e48 100644 --- a/infra-templates/secret-volume-driver/3/README.md +++ b/infra-templates/secret-volume-driver/3/README.md @@ -10,7 +10,7 @@ through an isolated in-memory filesystem. ## Security boundary The service uses -`ghcr.io/pasturestack/secrets-flexvolume-plugin:v0.1.1`. The Catalog and user +`ghcr.io/pasturestack/secrets-flexvolume-plugin:v0.2.1`. The Catalog and user interface intentionally use the semantic version tag without a manifest digest. diff --git a/infra-templates/secret-volume-driver/3/README.zh-TW.md b/infra-templates/secret-volume-driver/3/README.zh-TW.md index 2a15224e8..ded02839e 100644 --- a/infra-templates/secret-volume-driver/3/README.zh-TW.md +++ b/infra-templates/secret-volume-driver/3/README.zh-TW.md @@ -7,7 +7,7 @@ ## 安全性界線 -服務使用 `ghcr.io/pasturestack/secrets-flexvolume-plugin:v0.1.1`。 +服務使用 `ghcr.io/pasturestack/secrets-flexvolume-plugin:v0.2.1`。 商店與使用者介面只顯示語意化版本標籤,不顯示映像摘要。 容器: diff --git a/infra-templates/system-image-preloader/3/README.md b/infra-templates/system-image-preloader/3/README.md index 1f4764efa..475e3ae50 100644 --- a/infra-templates/system-image-preloader/3/README.md +++ b/infra-templates/system-image-preloader/3/README.md @@ -1,6 +1,6 @@ -# PastureStack System Image Preloader v0.3.0 +# PastureStack System Image Preloader v0.3.2 This global, start-once infrastructure service discovers the images used by compatible system stacks and asks each host Docker daemon to cache images that @@ -8,11 +8,11 @@ are not already present. ## Reviewed image -- Image: `ghcr.io/pasturestack/system-image-preloader:v0.3.0` -- Source: [`PastureStack/system-image-preloader@150c78dbdb3f487a7003c83339cca5b76dde97f4`](https://github.com/PastureStack/system-image-preloader/tree/150c78dbdb3f487a7003c83339cca5b76dde97f4) +- Image: `ghcr.io/pasturestack/system-image-preloader:v0.3.2` +- Source: [`PastureStack/system-image-preloader@bcd89e7fb6baafea381de380c256e4e8d62f1df2`](https://github.com/PastureStack/system-image-preloader/tree/bcd89e7fb6baafea381de380c256e4e8d62f1df2) - Source license: Apache-2.0; Ubuntu, Docker CLI, `yq`, `gomplate`, and their dependencies retain their upstream licenses and notices -- Security gate: Trivy HIGH 0 and CRITICAL 0 +- Security gate: full-severity scan, no available fix, no unreviewed finding or secret - Distribution gate: public GHCR and anonymous version-tag manifest access passed @@ -35,7 +35,7 @@ are protocol identifiers, not PastureStack branding. ## Validation The release passed offline retry and URL-contract tests, container help and -version smoke tests, OCI metadata and license checks, a current HIGH/CRITICAL +version smoke tests, OCI metadata and license checks, a full-severity vulnerability scan, and an isolated end-to-end lifecycle test. The lifecycle test used mock metadata, environment, and Catalog APIs and verified that the runtime discovered a Compose image and cached its semantic tag through a real diff --git a/infra-templates/system-image-preloader/3/README.zh-TW.md b/infra-templates/system-image-preloader/3/README.zh-TW.md index 7dcd5a591..f814b3c8e 100644 --- a/infra-templates/system-image-preloader/3/README.zh-TW.md +++ b/infra-templates/system-image-preloader/3/README.zh-TW.md @@ -1,18 +1,18 @@ -# PastureStack 系統映像預先下載 v0.3.0 +# PastureStack 系統映像預先下載 v0.3.2 此全域、只執行一次的基礎架構服務會找出相容系統堆疊使用的映像,並 要求每台主機的 Docker 常駐程式預先快取尚未存在的映像。 ## 已審核映像 -- 映像:`ghcr.io/pasturestack/system-image-preloader:v0.3.0` +- 映像:`ghcr.io/pasturestack/system-image-preloader:v0.3.2` - 原始碼: - [`PastureStack/system-image-preloader@150c78dbdb3f487a7003c83339cca5b76dde97f4`](https://github.com/PastureStack/system-image-preloader/tree/150c78dbdb3f487a7003c83339cca5b76dde97f4) + [`PastureStack/system-image-preloader@bcd89e7fb6baafea381de380c256e4e8d62f1df2`](https://github.com/PastureStack/system-image-preloader/tree/bcd89e7fb6baafea381de380c256e4e8d62f1df2) - 原始碼採 Apache-2.0 授權;Ubuntu、Docker CLI、`yq`、`gomplate` 及相依套件保留各自的上游授權及聲明。 -- Trivy 掃描結果為 HIGH 0、CRITICAL 0。 +- 完整嚴重度掃描沒有可用修補、未審核項目或機密資料;官方尚無修補的 Low/Medium 持續追蹤。 - 公開 GHCR 與未登入存取版本標籤的驗證已通過。 ## 安全性界線 diff --git a/infra-templates/system-image-preloader/3/docker-compose.yml.tpl b/infra-templates/system-image-preloader/3/docker-compose.yml.tpl index 7bcfa1f3a..1ed33b069 100644 --- a/infra-templates/system-image-preloader/3/docker-compose.yml.tpl +++ b/infra-templates/system-image-preloader/3/docker-compose.yml.tpl @@ -2,7 +2,7 @@ version: '2' services: system-image-preloader: - image: ghcr.io/pasturestack/system-image-preloader:v0.3.1 + image: ghcr.io/pasturestack/system-image-preloader:v0.3.2 {{ if eq .Values.PRIVILEGED "true"}} privileged: true {{ end}} diff --git a/infra-templates/system-image-preloader/3/rancher-compose.yml b/infra-templates/system-image-preloader/3/rancher-compose.yml index 9fa58a199..803b711c2 100644 --- a/infra-templates/system-image-preloader/3/rancher-compose.yml +++ b/infra-templates/system-image-preloader/3/rancher-compose.yml @@ -2,7 +2,7 @@ version: '2' .catalog: name: PastureStack System Image Preloader - version: v0.3.1 + version: v0.3.2 description: Preload the container images required by compatible infrastructure stacks. minimum_rancher_version: v1.6.15-rc1 labels: diff --git a/infra-templates/system-image-preloader/config.yml b/infra-templates/system-image-preloader/config.yml index cdbe17177..0f7bea940 100644 --- a/infra-templates/system-image-preloader/config.yml +++ b/infra-templates/system-image-preloader/config.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT name: System Image Preloader description: Preload the container images required by compatible infrastructure stacks. -version: v0.3.1 +version: v0.3.2 category: System maintainer: PastureStack contributors license: MIT template; Apache-2.0 image and bundled dependency licenses apply diff --git a/infra-templates/vault-volume-driver/4/README.md b/infra-templates/vault-volume-driver/4/README.md index 65dca5be3..a4e88f80a 100644 --- a/infra-templates/vault-volume-driver/4/README.md +++ b/infra-templates/vault-volume-driver/4/README.md @@ -52,12 +52,12 @@ bridge to revoke the child-token accessor and erases the memory-backed volume. ## Security boundary The bridge uses -`ghcr.io/pasturestack/vault-secrets-bridge:v0.1.1`. It runs as UID 65532, +`ghcr.io/pasturestack/vault-secrets-bridge:v0.1.2`. It runs as UID 65532, drops all Linux capabilities, uses a read-only root filesystem, and persists only an encrypted accessor record in its dedicated state volume. The driver uses -`ghcr.io/pasturestack/secrets-flexvolume-plugin:v0.2.0`. It drops all +`ghcr.io/pasturestack/secrets-flexvolume-plugin:v0.2.1`. It drops all capabilities before adding only `SYS_ADMIN`, `CHOWN`, and `FOWNER` for the isolated `tmpfs` lifecycle and requested read-only ownership. It does not use privileged mode, host networking, the host PID namespace, or a diff --git a/infra-templates/vault-volume-driver/4/README.zh-TW.md b/infra-templates/vault-volume-driver/4/README.zh-TW.md index fabfaa43a..388152b5e 100644 --- a/infra-templates/vault-volume-driver/4/README.zh-TW.md +++ b/infra-templates/vault-volume-driver/4/README.zh-TW.md @@ -48,12 +48,12 @@ volumes: ## 安全界線 橋接服務使用 -`ghcr.io/pasturestack/vault-secrets-bridge:v0.1.1`。程序以 UID 65532 +`ghcr.io/pasturestack/vault-secrets-bridge:v0.1.2`。程序以 UID 65532 執行、移除全部 Linux capabilities、使用唯讀根檔案系統,且只在專用狀態 磁碟區保存加密後的 Accessor 紀錄。 驅動程式使用 -`ghcr.io/pasturestack/secrets-flexvolume-plugin:v0.2.0`。程序先移除全部 +`ghcr.io/pasturestack/secrets-flexvolume-plugin:v0.2.1`。程序先移除全部 capabilities,再僅加入隔離 `tmpfs` 生命週期及指定唯讀擁有權所需的 `SYS_ADMIN`、`CHOWN` 與 `FOWNER`。它不使用特權模式、主機網路、主機 PID 命名空間或容器引擎 Socket。 diff --git a/infra-templates/vxlan-overlay-network/6/README.md b/infra-templates/vxlan-overlay-network/6/README.md index a24853b2a..6106e1565 100644 --- a/infra-templates/vxlan-overlay-network/6/README.md +++ b/infra-templates/vxlan-overlay-network/6/README.md @@ -1,6 +1,6 @@ -# PastureStack VXLAN Overlay Network 0.3.3 +# PastureStack VXLAN Overlay Network 0.3.4 This optional infrastructure template installs an unencrypted VXLAN data plane across managed hosts. It publishes UDP port `4789`, runs one router @@ -9,9 +9,9 @@ eligible host. ## Reviewed image -- Image: `ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.34` +- Image: `ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.40` - Template version `5` explicitly declares `allowSharedSubnetIngress: true` for the fixed `10.42.0.0/16` CNI network. Network Plugin Manager `v0.8.20` uses this bounded contract for cross-host workload forwarding; version `4` remains available for existing stacks. -- Source: [`PastureStack/ipsec-vxlan-overlay-network@db5a506346f521c6947b21a1a60cef6dd546f983`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/db5a506346f521c6947b21a1a60cef6dd546f983) +- Source: [`PastureStack/ipsec-vxlan-overlay-network@4711833178a05e5d225e364cce856bd108bdc707`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/4711833178a05e5d225e364cce856bd108bdc707) - Source license: Apache-2.0; Ubuntu, CNI, Weave, and bundled dependencies retain their upstream licenses and notices - Security gate: Trivy HIGH 0, CRITICAL 0, image secrets 0, and personal-marker scan passed - Runtime gate: the earlier version passed isolated two-node VXLAN forwarding; repeat the managed lifecycle gate for this new image before treating it as production-ready diff --git a/infra-templates/vxlan-overlay-network/6/README.zh-TW.md b/infra-templates/vxlan-overlay-network/6/README.zh-TW.md index d836ffc2f..9b764793f 100644 --- a/infra-templates/vxlan-overlay-network/6/README.zh-TW.md +++ b/infra-templates/vxlan-overlay-network/6/README.zh-TW.md @@ -1,6 +1,6 @@ -# PastureStack VXLAN 覆疊網路 0.3.3 +# PastureStack VXLAN 覆疊網路 0.3.4 此選用基礎架構範本會在受管主機間安裝未加密的 VXLAN 資料平面。 範本會公開 UDP `4789`、為每個網路持有服務執行一個路由相關容器, @@ -8,12 +8,12 @@ ## 已審核映像 -- 映像:`ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.34` +- 映像:`ghcr.io/pasturestack/ipsec-vxlan-overlay-network:v0.14.40` - 第 `5` 版為固定的 `10.42.0.0/16` CNI 網路明確設定 `allowSharedSubnetIngress: true`。網路外掛管理器 `v0.8.20` 依此有限 契約處理跨主機工作負載轉送;第 `4` 版仍供既有堆疊使用。 - 原始碼: - [`PastureStack/ipsec-vxlan-overlay-network@db5a506346f521c6947b21a1a60cef6dd546f983`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/db5a506346f521c6947b21a1a60cef6dd546f983) + [`PastureStack/ipsec-vxlan-overlay-network@4711833178a05e5d225e364cce856bd108bdc707`](https://github.com/PastureStack/ipsec-vxlan-overlay-network/tree/4711833178a05e5d225e364cce856bd108bdc707) - 原始碼採 Apache-2.0 授權;Ubuntu、CNI、Weave 及隨附相依套件 保留各自的上游授權及聲明。 - Trivy 結果為 HIGH 0、CRITICAL 0,映像機密資料與個人識別標記 diff --git a/integration/core/test_catalog.py b/integration/core/test_catalog.py index 4a70fa986..a2ca85019 100644 --- a/integration/core/test_catalog.py +++ b/integration/core/test_catalog.py @@ -280,7 +280,7 @@ def test_catalog_list(): assert by_folder[('infra', 'system-image-preloader')]['name'] == ( 'System Image Preloader') assert by_folder[('infra', 'system-image-preloader')][ - 'defaultVersion'] == 'v0.3.1' + 'defaultVersion'] == 'v0.3.2' assert by_folder[('infra', 'system-image-preloader')][ 'links']['defaultVersion'].endswith( ':3') @@ -968,7 +968,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): preloader_docker = preloader_files['docker-compose.yml.tpl'] preloader_platform = preloader_files['rancher-compose.yml'] preloader_image = ( - 'ghcr.io/pasturestack/system-image-preloader:v0.3.1') + 'ghcr.io/pasturestack/system-image-preloader:v0.3.2') assert preloader_docker.count( 'image: {}'.format(preloader_image)) == 1 assert '\n system-image-preloader:\n' in preloader_docker @@ -982,7 +982,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): assert '{{- if' not in preloader_docker assert '{{- end' not in preloader_docker assert '@sha256:' not in preloader_docker - assert 'ghcr.io/pasturestack/system-image-preloader:v0.3.1' in ( + assert 'ghcr.io/pasturestack/system-image-preloader:v0.3.2' in ( preloader_docker) assert 'default: v1.6.282' in preloader_platform assert 'default: false' in preloader_platform @@ -1176,10 +1176,10 @@ def test_catalog_compose_shapes_are_runtime_compatible(): ), ( 'system-image-preloader', '2', '3', - 'v0.3.0', 'v0.3.1', [ + 'v0.3.0', 'v0.3.2', [ ( 'system-image-preloader:v0.3.0', - 'system-image-preloader:v0.3.1', + 'system-image-preloader:v0.3.2', ), ], ), @@ -1289,7 +1289,7 @@ def test_october_security_revisions_preserve_contract( with open(_file(prefix + new_number + '/' + filename), encoding='utf-8') as source: assert source.read() == expected - for filename in ('rancher-compose.yml', 'README.md', 'README.zh-TW.md'): + for filename in ('rancher-compose.yml',): with open(_file(prefix + old_number + '/' + filename), encoding='utf-8') as source: expected = source.read() @@ -1300,6 +1300,20 @@ def test_october_security_revisions_preserve_contract( with open(_file(prefix + new_number + '/' + filename), encoding='utf-8') as source: assert source.read() == expected + # Documentation follows the new published inputs; runtime definitions above + # remain byte-identical apart from the reviewed image/version replacements. + for filename in ('README.md', 'README.zh-TW.md'): + with open(_file(prefix + old_number + '/' + filename), + encoding='utf-8') as source: + old_doc = source.read() + with open(_file(prefix + new_number + '/' + filename), + encoding='utf-8') as source: + new_doc = source.read() + assert new_doc.strip() + for old_image, new_image in replacements: + if old_image in old_doc: + assert new_image in new_doc + assert old_image not in new_doc for number in (old_number, new_number): retained = _get_json(_catalog_url( '/v1-catalog/templateversions/{}:infra*{}:{}'.format( @@ -1335,7 +1349,7 @@ def test_ipsec38_template_preserves_version11_contract(): encoding='utf-8') as source: catalog = source.read() assert catalog == old_catalog.replace( - ' version: v0.3.9\n', ' version: v0.3.10\n') + ' version: v0.3.9\n', ' version: v0.3.20\n') with open(_file('catalog-images.json'), encoding='utf-8') as source: images = { From 1c890c73f2e16de03af83a15f791a3c361f8e39e Mon Sep 17 00:00:00 2001 From: chen21019 <19357113+chen21019@users.noreply.github.com> Date: Sat, 24 Oct 2026 00:00:51 +0800 Subject: [PATCH 09/10] catalog: consume formally verified ECR 3.1.6 as retained revision --- README.md | 3 +- SUPPORTED.md | 2 +- catalog-images.json | 38 +++++ .../ecr-credential-sync/4/README.md | 56 ++++++ .../ecr-credential-sync/4/README.zh-TW.md | 48 ++++++ .../4/docker-compose.yml.tpl | 47 ++++++ .../ecr-credential-sync/4/rancher-compose.yml | 159 ++++++++++++++++++ .../ecr-credential-sync/config.yml | 2 +- integration/core/test_catalog.py | 15 +- scripts/audit_deployable_images.py | 2 +- 10 files changed, 365 insertions(+), 7 deletions(-) create mode 100644 infra-templates/ecr-credential-sync/4/README.md create mode 100644 infra-templates/ecr-credential-sync/4/README.zh-TW.md create mode 100644 infra-templates/ecr-credential-sync/4/docker-compose.yml.tpl create mode 100644 infra-templates/ecr-credential-sync/4/rancher-compose.yml diff --git a/README.md b/README.md index 371551af5..52d44f3b4 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,8 @@ New template revisions consume published PastureStack runtime artifacts built from verified upstream inputs. Image tags, producer commits, manifest digests, licenses and runtime evidence are recorded in [catalog-images.json](catalog-images.json). Deployable Compose definitions use numeric release tags, not digest suffixes. -Available fixes and unreviewed findings block the current security release gate. +New default runtime versions are accepted after their component security gates. +Available fixes and unreviewed findings block those component gates. Officially unfixed Low/Medium findings remain tracked, not resolved; narrowly scoped VEX decisions require product-specific evidence and retain the raw scan. A clean gate is not a claim that every dependency has zero reported CVEs. diff --git a/SUPPORTED.md b/SUPPORTED.md index 65e926ac2..9ed8b17fc 100644 --- a/SUPPORTED.md +++ b/SUPPORTED.md @@ -11,7 +11,7 @@ or out-of-scope templates from being presented as deployable software. | PastureStack Native | Project template | v0.3.0 | Composes only reviewed, semantic-versioned infrastructure entries | Clean single-host provisioning and restart passed; restored-data validation pending | | PastureStack Container Schedule | Infrastructure scheduling service | v0.6.1 | Public PastureStack GHCR image with an explicit version tag | Published component; exact runtime evidence is in catalog-images.json; environment upgrade/rollback remains separate | | PastureStack System Image Preloader | Infrastructure image-cache service | v0.3.2 | Public PastureStack GHCR image with an explicit version tag | Published component; exact runtime evidence is in catalog-images.json; environment upgrade/rollback remains separate | -| PastureStack Amazon ECR Credential Sync | Infrastructure registry service | v3.1.5 | Public PastureStack GHCR image with an explicit version tag | Source tests, anonymous distribution, and credential lifecycle gates passed | +| PastureStack Amazon ECR Credential Sync | Infrastructure registry service | v3.1.6 | Public PastureStack GHCR image with an explicit version tag | Published component; full runtime raw scan has zero findings; Catalog integration and environment acceptance remain distinct | | Metadata Healthcheck | Infrastructure stack | v0.3.17 | Public PastureStack GHCR image with a non-overwritten version tag | Published component; exact runtime evidence is in catalog-images.json; environment upgrade/rollback remains separate | | PastureStack Network Services | Infrastructure system stack | v0.3.9 | Published Network Plugin Manager v0.8.22; Metadata Service v0.9.11 and Internal DNS v0.17.11 unchanged | Published component; exact runtime evidence is in catalog-images.json; environment upgrade/rollback remains separate | | PastureStack Network Diagnostics | Infrastructure diagnostics service | v0.2.2 | Two public PastureStack GHCR images with explicit version tags | Published component; exact runtime evidence is in catalog-images.json; environment upgrade/rollback remains separate | diff --git a/catalog-images.json b/catalog-images.json index e608d1138..da2dae7bc 100644 --- a/catalog-images.json +++ b/catalog-images.json @@ -1420,6 +1420,44 @@ "sourceCommit": "35d3a67c62df4b22d7167da3d73dd9dbc4905e66" } } + }, + { + "sourceRepository": "https://github.com/PastureStack/ecr-credential-sync", + "sourcePath": "package/Dockerfile", + "registryPage": "https://github.com/orgs/PastureStack/packages/container/package/ecr-credential-sync", + "licenseBoundary": "Apache-2.0 source and image; bundled runtime and vendored Go dependencies retain their upstream licenses and notices", + "platforms": [ + "linux/amd64" + ], + "reference": "ghcr.io/pasturestack/ecr-credential-sync:v3.1.6", + "sourceCommit": "f59e103a4c5759519318d290a0c63f7b0614991c", + "manifestDigest": "sha256:ec59763343440bccfaa15640d526e1082d0d2da35e86b939890dfa25c4bee6a0", + "reviewedAt": "2026-10-23", + "vulnerabilityScan": { + "scope": "published runtime image", + "high": 0, + "critical": 0, + "evidence": "https://github.com/PastureStack/ecr-credential-sync/actions/runs/39978735904", + "low": 0, + "medium": 0, + "unknown": 0, + "secrets": 0, + "fixedAvailable": 0, + "actionable": 0, + "rawSha256": "03116ab10ec38db3b5fa234e6d955d84a3d16b246991315637d49c0eb31f0786" + }, + "publicationVerification": { + "source": "component owner verified anonymous manifest/config readback", + "workflowRun": "https://github.com/PastureStack/ecr-credential-sync/actions/runs/39978735904", + "sourceCommit": "f59e103a4c5759519318d290a0c63f7b0614991c", + "anonymousReadback": true, + "attestationVerified": true + }, + "sbom": { + "format": "CycloneDX", + "sha256": "a448ff8fcdaf1d124c04a9787552077d3b9b1467548586dcd297d55258e7dc77", + "url": "https://github.com/PastureStack/ecr-credential-sync/releases/download/v3.1.6/ecr-credential-sync-3.1.6-image.cdx.json" + } } ] } diff --git a/infra-templates/ecr-credential-sync/4/README.md b/infra-templates/ecr-credential-sync/4/README.md new file mode 100644 index 000000000..3eeeb1144 --- /dev/null +++ b/infra-templates/ecr-credential-sync/4/README.md @@ -0,0 +1,56 @@ + + +# PastureStack Amazon ECR Credential Sync v3.1.6 + +This infrastructure service refreshes the short-lived Docker registry +credentials returned by Amazon Elastic Container Registry. It synchronizes +immediately after startup and every six hours thereafter. + +## Reviewed image + +- Image: `ghcr.io/pasturestack/ecr-credential-sync:v3.1.6` +- Source: [`PastureStack/ecr-credential-sync@v3.1.6`](https://github.com/PastureStack/ecr-credential-sync/tree/v3.1.6) +- Upstream: [`rancher/rancher-ecr-credentials`](https://github.com/rancher/rancher-ecr-credentials) +- Source license: Apache-2.0; bundled runtime and vendored Go dependencies retain their + upstream licenses and notices +- Runtime user: `10001:10001` +- Security gate: the published runtime's complete all-severity Trivy report has + zero vulnerability and secret findings +- Distribution gate: public GHCR and anonymous version-tag manifest access + passed + +PastureStack is an independent community effort to preserve, audit, and +modernize the Rancher 1.6 ecosystem. It is not affiliated with or endorsed by +Rancher Labs or SUSE. + +## Security boundary + +Use an environment-scoped API key and the least-privilege AWS permissions +required to call the ECR authorization-token API. Password questions are +masked in the launch form, but the deployed service still receives those +values as container environment variables. Restrict access to the stack, +service configuration, and host runtime. + +For the current environment, the compatible control plane injects its +environment API credentials through the literal `io.rancher.*` agent labels +and historical `CATTLE_*` variables. The startup command maps those protocol +identifiers to the neutral `PLATFORM_*` runtime contract. They are compatibility +identifiers, not PastureStack branding. + +The shared AWS profile mount is disabled by default. When enabled, the selected +host directory is mounted read-only at `/home/pasturestack/.aws`. The service +does not require privileged mode, host networking, a Docker socket, or host +filesystem access beyond that optional credential directory. + +## Validation and lifecycle + +The release passed race-enabled unit tests, static analysis, mock Amazon ECR +request signing, registry and credential create/update integration tests, +health endpoint checks, non-root and OCI metadata checks, license-file +verification, full-severity vulnerability and secret scans, and an +isolated container lifecycle test. Logs were checked to ensure that AWS, +environment API, authorization-token, and role credentials were not exposed. + +To roll back, upgrade this stack to the previously reviewed Catalog revision +and semantic image tag. Remove only the exact stack, service, and optional +profile mount created for this component; no broad host cleanup is required. diff --git a/infra-templates/ecr-credential-sync/4/README.zh-TW.md b/infra-templates/ecr-credential-sync/4/README.zh-TW.md new file mode 100644 index 000000000..ef2822073 --- /dev/null +++ b/infra-templates/ecr-credential-sync/4/README.zh-TW.md @@ -0,0 +1,48 @@ + + +# PastureStack Amazon ECR 登入資訊同步 v3.1.6 + +此基礎架構服務會更新 Amazon Elastic Container Registry 提供的短效 +Docker 登入資訊。服務啟動後會立即同步,之後每六小時同步一次。 + +## 已審核映像 + +- 映像:`ghcr.io/pasturestack/ecr-credential-sync:v3.1.6` +- 原始碼: + [`PastureStack/ecr-credential-sync@v3.1.6`](https://github.com/PastureStack/ecr-credential-sync/tree/v3.1.6) +- 上游: + [`rancher/rancher-ecr-credentials`](https://github.com/rancher/rancher-ecr-credentials) +- 原始碼採 Apache-2.0 授權;隨附的 runtime 與 Go 相依套件保留各自 + 的上游授權及聲明。 +- 執行身分:`10001:10001` +- 正式 runtime 的完整 severity 原始掃描為 0 筆弱點、0 筆機密資料。 +- 公開 GHCR 與未登入存取版本標籤的驗證已通過。 + +PastureStack 是獨立的社群計畫,目的在保存、稽核與現代化 Rancher +1.6 生態系;本計畫與 Rancher Labs 或 SUSE 無隸屬或背書關係。 + +## 安全性界線 + +請使用環境範圍的 API 金鑰,並只授予呼叫 ECR 授權權杖 API 所需的 +最小 AWS 權限。啟動表單會遮蔽密碼欄位,但部署後服務仍會從容器環境 +變數取得這些值,因此必須限制堆疊、服務設定與主機執行環境的存取權限。 + +同步目前環境時,相容控制平面會透過 `io.rancher.*` 代理程式標籤及 +歷史 `CATTLE_*` 變數注入環境 API 登入資訊。啟動命令會把這些相容 +協定識別名稱映射到中性的 `PLATFORM_*` 執行契約。 + +共用 AWS 設定檔掛載預設為停用。啟用後,選取的主機目錄會以唯讀方式 +掛載到 `/home/pasturestack/.aws`。服務不需要特權模式、主機網路、 +Docker Socket,也不會存取該選用登入資訊目錄以外的主機檔案系統。 + +## 驗證與生命週期 + +此版本已通過啟用競爭偵測的單元測試、靜態分析、模擬 Amazon ECR +請求簽章、登錄與登入資訊建立/更新整合測試、健康狀態端點、非 root +執行、OCI 中繼資料、授權檔、弱點及機密資料掃描,以及隔離容器生命 +週期測試。日誌檢查也確認不會洩漏 AWS、環境 API、授權權杖或角色 +登入資訊。 + +需要回復時,請把此堆疊升級到先前已審核的商店修訂版與語意化映像 +標籤。只移除這個元件建立的精確堆疊、服務及選用設定檔掛載,不需進行 +大範圍主機清理。 diff --git a/infra-templates/ecr-credential-sync/4/docker-compose.yml.tpl b/infra-templates/ecr-credential-sync/4/docker-compose.yml.tpl new file mode 100644 index 000000000..e763f289e --- /dev/null +++ b/infra-templates/ecr-credential-sync/4/docker-compose.yml.tpl @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: MIT +version: '2' +services: + ecr-credential-sync: + image: ghcr.io/pasturestack/ecr-credential-sync:v3.1.6 + entrypoint: + - /bin/sh + - -ec + command: + - | + export PLATFORM_URL="$${PLATFORM_URL:-$${CATTLE_URL:-}}" + export PLATFORM_ACCESS_KEY="$${PLATFORM_ACCESS_KEY:-$${CATTLE_ACCESS_KEY:-}}" + export PLATFORM_SECRET_KEY="$${PLATFORM_SECRET_KEY:-$${CATTLE_SECRET_KEY:-}}" + exec /usr/local/bin/ecr-credential-sync + environment: + AUTO_CREATE: '${AUTO_CREATE}' + AWS_ACCESS_KEY_ID: '${AWS_ACCESS_KEY_ID}' + AWS_ECR_ENDPOINT_URL: '${AWS_ECR_ENDPOINT_URL}' + AWS_ECR_REGISTRY_IDS: '${AWS_ECR_REGISTRY_IDS}' + AWS_PROFILE: '${AWS_PROFILE}' + AWS_REGION: '${AWS_REGION}' + AWS_ROLE_ARN: '${AWS_ROLE_ARN}' + AWS_SECRET_ACCESS_KEY: '${AWS_SECRET_ACCESS_KEY}' + AWS_SESSION_TOKEN: '${AWS_SESSION_TOKEN}' + LISTEN_PORT: '8080' + LOG_LEVEL: '${LOG_LEVEL}' + {{ if eq .Values.REGISTRY_ENVIRONMENT "other"}} + PLATFORM_URL: '${PLATFORM_URL}' + PLATFORM_ACCESS_KEY: '${PLATFORM_ACCESS_KEY}' + PLATFORM_SECRET_KEY: '${PLATFORM_SECRET_KEY}' + {{ end}} + {{ if eq .Values.USE_SHARED_AWS_PROFILE "true"}} + volumes: + - ${AWS_PROFILE_DIRECTORY}:/home/pasturestack/.aws:ro + {{ end}} + {{ if eq .Values.REGISTRY_ENVIRONMENT "current"}} + labels: + io.rancher.container.create_agent: 'true' + io.rancher.container.agent.role: environment + {{ end}} + cpu_shares: 128 + mem_limit: 128m + logging: + driver: json-file + options: + max-size: 10m + max-file: '2' diff --git a/infra-templates/ecr-credential-sync/4/rancher-compose.yml b/infra-templates/ecr-credential-sync/4/rancher-compose.yml new file mode 100644 index 000000000..d3ff8f573 --- /dev/null +++ b/infra-templates/ecr-credential-sync/4/rancher-compose.yml @@ -0,0 +1,159 @@ +# SPDX-License-Identifier: MIT +version: '2' +.catalog: + name: PastureStack Amazon ECR Credential Sync + version: v3.1.6 + description: Refresh short-lived Amazon Elastic Container Registry credentials in a compatible environment. + minimum_rancher_version: v1.6.13-rc1 + labels: + io.pasturestack.catalog.question.aws_region.label.zh-tw: 'AWS 區域' + io.pasturestack.catalog.question.aws_region.description.zh-tw: 'Amazon ECR 登錄所在的 AWS 區域。' + io.pasturestack.catalog.question.aws_access_key_id.label.zh-tw: 'AWS 存取金鑰識別碼' + io.pasturestack.catalog.question.aws_access_key_id.description.zh-tw: '由 IAM 角色、共用設定檔或 EC2 執行個體身分提供登入資訊時可留空。' + io.pasturestack.catalog.question.aws_secret_access_key.label.zh-tw: 'AWS 私密存取金鑰' + io.pasturestack.catalog.question.aws_secret_access_key.description.zh-tw: '與 AWS 存取金鑰識別碼配對的私密金鑰。' + io.pasturestack.catalog.question.aws_session_token.label.zh-tw: 'AWS 工作階段權杖' + io.pasturestack.catalog.question.aws_session_token.description.zh-tw: '使用 AWS 臨時登入資訊時提供的選用權杖。' + io.pasturestack.catalog.question.aws_role_arn.label.zh-tw: 'AWS IAM 角色 ARN' + io.pasturestack.catalog.question.aws_role_arn.description.zh-tw: '要求 Amazon ECR 授權權杖前要擔任的選用 IAM 角色。' + io.pasturestack.catalog.question.aws_ecr_registry_ids.label.zh-tw: 'AWS 帳戶識別碼' + io.pasturestack.catalog.question.aws_ecr_registry_ids.description.zh-tw: '要同步的 12 位數 AWS 帳戶識別碼,以半形逗號分隔;留空時使用預設登錄。' + io.pasturestack.catalog.question.auto_create.label.zh-tw: '建立缺少的登錄' + io.pasturestack.catalog.question.auto_create.description.zh-tw: '找不到相符登錄時,自動建立登錄與登入資訊紀錄。' + io.pasturestack.catalog.question.use_shared_aws_profile.label.zh-tw: '掛載共用 AWS 設定檔' + io.pasturestack.catalog.question.use_shared_aws_profile.description.zh-tw: '掛載含有 AWS 登入資訊及設定檔的主機目錄。' + io.pasturestack.catalog.question.aws_profile_directory.label.zh-tw: '共用 AWS 設定檔目錄' + io.pasturestack.catalog.question.aws_profile_directory.description.zh-tw: '含有 AWS 登入資訊及設定檔的主機絕對路徑。' + io.pasturestack.catalog.question.aws_profile.label.zh-tw: 'AWS 設定檔名稱' + io.pasturestack.catalog.question.aws_profile.description.zh-tw: '掛載之共用 AWS 設定中的選用設定檔名稱。' + io.pasturestack.catalog.question.registry_environment.label.zh-tw: '登錄所在環境' + io.pasturestack.catalog.question.registry_environment.description.zh-tw: '選擇同步目前環境或另一個相容環境。' + io.pasturestack.catalog.question.platform_url.label.zh-tw: '其他環境 API 網址' + io.pasturestack.catalog.question.platform_url.description.zh-tw: '只有同步其他環境時才需要;請使用該環境範圍的 API 端點。' + io.pasturestack.catalog.question.platform_access_key.label.zh-tw: '其他環境 API 存取金鑰' + io.pasturestack.catalog.question.platform_access_key.description.zh-tw: '只有同步其他環境時才需要;請使用該環境範圍的存取金鑰。' + io.pasturestack.catalog.question.platform_secret_key.label.zh-tw: '其他環境 API 私密金鑰' + io.pasturestack.catalog.question.platform_secret_key.description.zh-tw: '只有同步其他環境時才需要;請使用配對且限於該環境的私密金鑰。' + io.pasturestack.catalog.question.aws_ecr_endpoint_url.label.zh-tw: '替代 ECR API 端點' + io.pasturestack.catalog.question.aws_ecr_endpoint_url.description.zh-tw: 'AWS 相容 ECR API 或隔離驗證環境使用的選用 HTTP(S) 端點。' + io.pasturestack.catalog.question.log_level.label.zh-tw: '日誌詳細程度' + io.pasturestack.catalog.question.log_level.description.zh-tw: '服務執行期間要記錄的詳細程度。' + questions: + - variable: AWS_REGION + label: AWS region + description: AWS region that contains the Amazon ECR registry. + type: string + default: us-east-1 + required: true + - variable: AWS_ACCESS_KEY_ID + label: AWS access key ID + description: Optional when an IAM role, shared profile, or EC2 instance identity supplies credentials. + type: string + default: '' + required: false + - variable: AWS_SECRET_ACCESS_KEY + label: AWS secret access key + description: Secret paired with the AWS access key ID. + type: password + default: '' + required: false + - variable: AWS_SESSION_TOKEN + label: AWS session token + description: Optional token for temporary AWS credentials. + type: password + default: '' + required: false + - variable: AWS_ROLE_ARN + label: AWS IAM role ARN + description: Optional IAM role to assume before requesting Amazon ECR authorization tokens. + type: string + default: '' + required: false + - variable: AWS_ECR_REGISTRY_IDS + label: AWS account IDs + description: Optional comma-separated list of 12-digit AWS account IDs; blank requests the default registry. + type: string + default: '' + required: false + - variable: AUTO_CREATE + label: Create missing registry + description: Create a registry and credential record when no matching registry exists. + type: boolean + default: false + required: true + - variable: USE_SHARED_AWS_PROFILE + label: Mount a shared AWS profile + description: Mount a host directory containing AWS credentials and configuration files. + type: boolean + default: false + required: true + - variable: AWS_PROFILE_DIRECTORY + label: Shared AWS profile directory + description: Absolute host path containing the AWS credentials and configuration files. + type: string + default: /root/.aws + required: true + - variable: AWS_PROFILE + label: AWS profile name + description: Optional profile name from the mounted shared AWS configuration. + type: string + default: '' + required: false + - variable: REGISTRY_ENVIRONMENT + label: Registry environment + description: Synchronize the current environment or another compatible environment. + type: enum + default: current + required: true + options: + - current + - other + - variable: PLATFORM_URL + label: Other environment API URL + description: Required only when synchronizing another environment; use its environment-scoped API endpoint. + type: string + default: '' + required: false + - variable: PLATFORM_ACCESS_KEY + label: Other environment API access key + description: Required only when synchronizing another environment; use an environment-scoped access key. + type: password + default: '' + required: false + - variable: PLATFORM_SECRET_KEY + label: Other environment API secret key + description: Required only when synchronizing another environment; use the matching environment-scoped secret key. + type: password + default: '' + required: false + - variable: AWS_ECR_ENDPOINT_URL + label: Alternate ECR API endpoint + description: Optional HTTP(S) endpoint for an AWS-compatible ECR API or isolated validation. + type: string + default: '' + required: false + - variable: LOG_LEVEL + label: Log level + description: Runtime log detail. + type: enum + default: info + required: true + options: + - error + - warn + - info + - debug + +ecr-credential-sync: + scale: 1 + start_on_create: true + health_check: + request_line: GET /ping HTTP/1.0 + port: 8080 + interval: 10000 + initializing_timeout: 60000 + reinitializing_timeout: 60000 + response_timeout: 3000 + healthy_threshold: 2 + unhealthy_threshold: 3 + strategy: none diff --git a/infra-templates/ecr-credential-sync/config.yml b/infra-templates/ecr-credential-sync/config.yml index 4f3b7e1e3..b1171479c 100644 --- a/infra-templates/ecr-credential-sync/config.yml +++ b/infra-templates/ecr-credential-sync/config.yml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT name: Amazon ECR Credential Sync description: Refresh short-lived Amazon Elastic Container Registry credentials in a compatible environment. -version: v3.1.5 +version: v3.1.6 category: Registry maintainer: PastureStack contributors license: MIT template; Apache-2.0 image and bundled dependency licenses apply diff --git a/integration/core/test_catalog.py b/integration/core/test_catalog.py index a2ca85019..49f9ba7b7 100644 --- a/integration/core/test_catalog.py +++ b/integration/core/test_catalog.py @@ -190,10 +190,10 @@ def test_catalog_list(): assert by_folder[('infra', 'ecr-credential-sync')][ 'name'] == 'Amazon ECR Credential Sync' assert by_folder[('infra', 'ecr-credential-sync')][ - 'defaultVersion'] == 'v3.1.5' + 'defaultVersion'] == 'v3.1.6' assert by_folder[('infra', 'ecr-credential-sync')][ 'links']['defaultVersion'].endswith( - ':3') + ':4') assert by_folder[('infra', 'healthcheck')][ 'name'] == 'Metadata Healthcheck' assert by_folder[('infra', 'healthcheck')][ @@ -521,7 +521,7 @@ def test_catalog_compose_shapes_are_runtime_compatible(): ecr_files = ecr_version['files'] ecr_docker = ecr_files['docker-compose.yml.tpl'] ecr_platform = ecr_files['rancher-compose.yml'] - ecr_image = 'ghcr.io/pasturestack/ecr-credential-sync:v3.1.5' + ecr_image = 'ghcr.io/pasturestack/ecr-credential-sync:v3.1.6' assert ecr_docker.count('image: {}'.format(ecr_image)) == 1 assert '\n ecr-credential-sync:\n' in ecr_docker assert '$${PLATFORM_URL:-$${CATTLE_URL:-}}' in ecr_docker @@ -1273,6 +1273,15 @@ def test_catalog_compose_shapes_are_runtime_compatible(): ), ], ), + ( + 'ecr-credential-sync', '3', '4', + 'v3.1.5', 'v3.1.6', [ + ( + 'ecr-credential-sync:v3.1.5', + 'ecr-credential-sync:v3.1.6', + ), + ], + ), ]) def test_october_security_revisions_preserve_contract( template, old_number, new_number, old_version, new_version, diff --git a/scripts/audit_deployable_images.py b/scripts/audit_deployable_images.py index 0abdc494c..306adb931 100644 --- a/scripts/audit_deployable_images.py +++ b/scripts/audit_deployable_images.py @@ -54,7 +54,7 @@ "amazon-efs-storage": ("2", "3"), "amazon-ebs-storage": ("2", "3"), "container-schedule": ("2", "3"), - "ecr-credential-sync": ("2", "3"), + "ecr-credential-sync": ("2", "3", "4"), "healthcheck": ("0", "1", "2"), "ipsec-overlay": ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13"), "layer-2-flat-network": ("2", "3", "4", "5", "6", "7"), From 12efcddeb092bc56b329e48f85d04112d38e5fce Mon Sep 17 00:00:00 2001 From: chen21019 <19357113+chen21019@users.noreply.github.com> Date: Sat, 24 Oct 2026 00:05:57 +0800 Subject: [PATCH 10/10] test: preserve the published IPsec revision 12 version oracle --- integration/core/test_catalog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration/core/test_catalog.py b/integration/core/test_catalog.py index 49f9ba7b7..9584852ff 100644 --- a/integration/core/test_catalog.py +++ b/integration/core/test_catalog.py @@ -1358,7 +1358,7 @@ def test_ipsec38_template_preserves_version11_contract(): encoding='utf-8') as source: catalog = source.read() assert catalog == old_catalog.replace( - ' version: v0.3.9\n', ' version: v0.3.20\n') + ' version: v0.3.9\n', ' version: v0.3.10\n') with open(_file('catalog-images.json'), encoding='utf-8') as source: images = {