├── .github └── workflows │ └── docker-build.yml ├── CHANGELOG.md ├── Dockerfile ├── README.md ├── docker-compose.yml.example ├── entrypoint.sh ├── package.json ├── results.sarif └── sbom.spdx.json /.github/workflows/docker-build.yml: -------------------------------------------------------------------------------- 1 | name: Publish Docker Image 2 | permissions: 3 | actions: read 4 | checks: read 5 | contents: write 6 | deployments: read 7 | issues: read 8 | discussions: read 9 | packages: read 10 | pages: read 11 | pull-requests: read 12 | repository-projects: read 13 | security-events: write 14 | statuses: read 15 | 16 | on: 17 | pull_request: 18 | branches: 19 | - main 20 | push: 21 | branches: 22 | - main 23 | 24 | env: 25 | REGISTRY_IMAGE: registry.dangerous.tech/dangeroustech/zerotierbridge 26 | 27 | jobs: 28 | Docker_Build: 29 | name: Docker Build And Release 30 | runs-on: ubuntu-latest 31 | strategy: 32 | fail-fast: true 33 | matrix: 34 | arch: [amd64, arm64] 35 | version: [1.12.2] 36 | steps: 37 | - name: Checkout Repository 38 | uses: actions/checkout@v4 39 | 40 | - name: Set up QEMU 41 | uses: docker/setup-qemu-action@v3 42 | 43 | - name: Set up Docker Buildx 44 | uses: docker/setup-buildx-action@v3 45 | 46 | - name: Login to Registry 47 | id: login 48 | uses: docker/login-action@v3 49 | with: 50 | registry: registry.dangerous.tech 51 | username: ${{ secrets.REGISTRY_USERNAME }} 52 | password: ${{ secrets.REGISTRY_PASSWORD }} 53 | 54 | - name: Build 55 | id: docker_build 56 | uses: docker/build-push-action@v5 57 | with: 58 | context: . 59 | build-args: | 60 | ARCH=${{ matrix.arch }} 61 | VERSION=${{ matrix.version }} 62 | push: true 63 | platforms: linux/${{ matrix.arch }} 64 | outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true 65 | 66 | - name: Export Digests 67 | run: | 68 | mkdir -p /tmp/digests 69 | digest="${{ steps.docker_build.outputs.digest }}" 70 | touch "/tmp/digests/${digest#sha256:}" 71 | 72 | - name: Upload digest 73 | uses: actions/upload-artifact@v3 74 | with: 75 | name: digests 76 | path: /tmp/digests/* 77 | if-no-files-found: error 78 | retention-days: 1 79 | 80 | MergeRefs: 81 | name: Do The Horrible Merge Thing 82 | if: github.ref == 'refs/heads/main' 83 | runs-on: ubuntu-latest 84 | needs: 85 | - Docker_Build 86 | steps: 87 | - name: Download digests 88 | uses: actions/download-artifact@v3 89 | with: 90 | name: digests 91 | path: /tmp/digests 92 | 93 | - name: Set up Docker Buildx 94 | uses: docker/setup-buildx-action@v3 95 | 96 | - name: Login to Registry 97 | id: login 98 | uses: docker/login-action@v3 99 | with: 100 | registry: registry.dangerous.tech 101 | username: ${{ secrets.REGISTRY_USERNAME }} 102 | password: ${{ secrets.REGISTRY_PASSWORD }} 103 | 104 | - name: Docker meta 105 | id: meta 106 | uses: docker/metadata-action@v5 107 | with: 108 | images: ${{ env.REGISTRY_IMAGE }} 109 | tags: | 110 | # set latest tag for default branch 111 | # https://github.com/docker/metadata-action#latest-tag 112 | type=raw,value=latest,enable={{is_default_branch}} 113 | 114 | - name: Create manifest list and push 115 | working-directory: /tmp/digests 116 | run: | 117 | docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ 118 | $(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *) 119 | - name: Inspect image 120 | run: | 121 | docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }} 122 | 123 | - name: Generate SBOM 124 | uses: anchore/sbom-action@v0 125 | id: sbom 126 | with: 127 | image: registry.dangerous.tech/dangeroustech/zerotierbridge:latest 128 | registry-username: ${{ secrets.REGISTRY_USERNAME }} 129 | registry-password: ${{ secrets.REGISTRY_PASSWORD }} 130 | format: spdx-json 131 | output-file: ./sbom.spdx.json 132 | 133 | - name: Scan SBOM 134 | uses: anchore/scan-action@v3 135 | id: scan 136 | with: 137 | sbom: sbom.spdx.json 138 | severity-cutoff: medium 139 | fail-build: false 140 | only-fixed: true 141 | 142 | - name: upload Anchore scan SARIF report 143 | uses: github/codeql-action/upload-sarif@v2 144 | with: 145 | sarif_file: ${{ steps.scan.outputs.sarif }} 146 | 147 | - name: Checkout Repository 148 | uses: actions/checkout@v4 149 | 150 | - name: Changelog 151 | uses: TriPSs/conventional-changelog-action@v3 152 | id: changelog 153 | if: ${{ github.event_name != 'pull_request' }} 154 | with: 155 | github-token: ${{ secrets.GITHUB_TOKEN }} 156 | git-message: "chore 🤖: Release {version}" 157 | output-file: CHANGELOG.md 158 | tag-prefix: v 159 | fallback-version: 1.0.0 160 | release-count: 0 # preserve all versions in changelog 161 | skip-on-empty: false # otherwise we don't publish fixes 162 | 163 | - name: Create Release 164 | uses: softprops/action-gh-release@v1 165 | id: release 166 | if: ${{ steps.changelog.outputs.skipped == 'false' }} 167 | env: 168 | GITHUB_TOKEN: ${{ secrets.github_token }} 169 | with: 170 | tag_name: ${{ steps.changelog.outputs.tag }} 171 | name: ${{ steps.changelog.outputs.tag }} 172 | body: ${{ steps.changelog.outputs.clean_changelog }} 173 | files: | 174 | sbom.spdx.json 175 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [1.1.2](https://github.com/dangeroustech/ZeroTierBridge/compare/v1.1.1...v1.1.2) (2023-10-18) 2 | 3 | 4 | 5 | ## [1.1.1](https://github.com/dangeroustech/ZeroTierBridge/compare/v1.1.0...v1.1.1) (2023-10-17) 6 | 7 | 8 | ### Bug Fixes 9 | 10 | * 401 ([bca9ec3](https://github.com/dangeroustech/ZeroTierBridge/commit/bca9ec3df76f9c6ea114e099dd9317c58489d0b2)) 11 | * correct deps ([be55349](https://github.com/dangeroustech/ZeroTierBridge/commit/be55349cefbf291a9ce4233e65a785dad4ec3830)) 12 | * correct multiplatform builds ([593036c](https://github.com/dangeroustech/ZeroTierBridge/commit/593036c8ad8099a3a4e7b1ac9b1dcfbdb8e04a98)) 13 | * push by digest again ([8d55074](https://github.com/dangeroustech/ZeroTierBridge/commit/8d550748cde552ef5552e02770842d4e91f99253)) 14 | * push by digest is breaking things ([2c987a3](https://github.com/dangeroustech/ZeroTierBridge/commit/2c987a3bbe0492aaf22b26e446cb7d96a6c9115d)) 15 | * re-setup buildx ([f8d7326](https://github.com/dangeroustech/ZeroTierBridge/commit/f8d73263fdfd328ad38a77ff381e93bd8bda5750)) 16 | * remove tag to hopefully fix digest pushing ([5cd683c](https://github.com/dangeroustech/ZeroTierBridge/commit/5cd683cb7a83e37eb5b4717309d672f35b256c25)) 17 | * set latest tag ([46ee60c](https://github.com/dangeroustech/ZeroTierBridge/commit/46ee60cbc9091e93f977701a771ba9ce0216e5d1)) 18 | 19 | 20 | 21 | # [1.1.0](https://github.com/dangeroustech/ZeroTierBridge/compare/v1.0.13...v1.1.0) (2023-09-23) 22 | 23 | 24 | ### Features 25 | 26 | * multi-platform builds ([aab5c07](https://github.com/dangeroustech/ZeroTierBridge/commit/aab5c079dcd559b7c3123aa72d02f7691827083e)) 27 | 28 | 29 | 30 | ## [1.0.13](https://github.com/dangeroustech/ZeroTierBridge/compare/v1.0.12...v1.0.13) (2023-09-22) 31 | 32 | 33 | 34 | ## [1.0.12](https://github.com/dangeroustech/ZeroTierBridge/compare/v1.0.11...v1.0.12) (2023-09-22) 35 | 36 | 37 | ### Bug Fixes 38 | 39 | * correct double message ([6e3c269](https://github.com/dangeroustech/ZeroTierBridge/commit/6e3c2690fc612e42c1d2818cc8d4bdfb9d5e39ba)) 40 | 41 | 42 | 43 | ## [1.0.11](https://github.com/dangeroustech/ZeroTierBridge/compare/v1.0.10...v1.0.11) (2023-09-22) 44 | 45 | 46 | ### Bug Fixes 47 | 48 | * only alert on CVEs that have a fix ([977df48](https://github.com/dangeroustech/ZeroTierBridge/commit/977df48644e0a7112dc25f9f04afa6d84ce87db9)) 49 | * pull correct deb package ([fed1c28](https://github.com/dangeroustech/ZeroTierBridge/commit/fed1c2860230d39aeb80178c79697c1c41fed23d)) 50 | 51 | 52 | 53 | ## [1.0.10](https://github.com/dangeroustech/ZeroTierBridge/compare/v1.0.9...v1.0.10) (2023-09-22) 54 | 55 | 56 | ### Bug Fixes 57 | 58 | * upload sarif file ([89e2953](https://github.com/dangeroustech/ZeroTierBridge/commit/89e29531f070539935a93b6f55d791170ea42e72)) 59 | 60 | 61 | 62 | ## [1.0.9](https://github.com/dangeroustech/ZeroTierBridge/compare/v1.0.8...v1.0.9) (2023-09-22) 63 | 64 | 65 | 66 | ## [1.0.8](https://github.com/dangeroustech/ZeroTierBridge/compare/v1.0.7...v1.0.8) (2023-09-22) 67 | 68 | 69 | 70 | ## [1.0.7](https://github.com/dangeroustech/ZeroTierBridge/compare/v1.0.6...v1.0.7) (2023-09-22) 71 | 72 | 73 | 74 | ## [1.0.6](https://github.com/dangeroustech/ZeroTierBridge/compare/v0.0.1...v1.0.6) (2023-09-22) 75 | 76 | 77 | 78 | ## [1.0.5](https://github.com/dangeroustech/ZeroTierBridge/compare/v1.0.4...v1.0.5) (2023-09-22) 79 | 80 | 81 | 82 | ## [1.0.4](https://github.com/dangeroustech/ZeroTierBridge/compare/v1.0.3...v1.0.4) (2023-09-22) 83 | 84 | 85 | 86 | ## [1.0.3](https://github.com/dangeroustech/ZeroTierBridge/compare/v1.0.2...v1.0.3) (2023-09-22) 87 | 88 | 89 | 90 | ## [1.0.2](https://github.com/dangeroustech/ZeroTierBridge/compare/v1.0.1...v1.0.2) (2023-09-22) 91 | 92 | 93 | ### Bug Fixes 94 | 95 | * quick filter to not release on PRs ([c34324b](https://github.com/dangeroustech/ZeroTierBridge/commit/c34324b998690edeadd3d680987587c0fe93c525)) 96 | 97 | 98 | 99 | ## [1.0.1](https://github.com/dangeroustech/ZeroTierBridge/compare/v1.0.0...v1.0.1) (2023-09-22) 100 | 101 | 102 | 103 | # [1.0.0](https://github.com/dangeroustech/ZeroTierBridge/compare/f902dcc0c4615801fb65e6c90342efe96789319f...v1.0.0) (2023-09-22) 104 | 105 | 106 | ### Bug Fixes 107 | 108 | * add openssl dep and remove pinning ([1298cea](https://github.com/dangeroustech/ZeroTierBridge/commit/1298cea4fa1bad3141754e5218f449ec15e8469a)) 109 | * allow bi-directional traffic initiation ([90cf5b1](https://github.com/dangeroustech/ZeroTierBridge/commit/90cf5b1684b6221797b39af306c3fee9ce5bdb9e)) 110 | * ci: lowercase tag names ([fc24b78](https://github.com/dangeroustech/ZeroTierBridge/commit/fc24b78d4a1046ebc2b01560ed4b67e33418c30e)) 111 | * ci: use correct registry ([3b29bee](https://github.com/dangeroustech/ZeroTierBridge/commit/3b29bee4c642cf04c3af89a7c16f004531f83622)) 112 | * ci: use full registry name ([3a5eb50](https://github.com/dangeroustech/ZeroTierBridge/commit/3a5eb50b13cf7cab7939c4b49c14093189aae330)) 113 | * set proper workdir ([7f56fec](https://github.com/dangeroustech/ZeroTierBridge/commit/7f56fec6897635e37b3e5aa13e7c3bbfddbce5da)) 114 | * standardise network env again ([3e65156](https://github.com/dangeroustech/ZeroTierBridge/commit/3e65156a3c955fa6c6715a7d9e15a799c6f3f735)) 115 | 116 | 117 | ### Features 118 | 119 | * add docker-compose.yml ([f902dcc](https://github.com/dangeroustech/ZeroTierBridge/commit/f902dcc0c4615801fb65e6c90342efe96789319f)) 120 | * support multiple zt network joins ([556195c](https://github.com/dangeroustech/ZeroTierBridge/commit/556195cd64f33fbbc9244022c8a99af5284ffbb9)) 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bookworm as stage 2 | ARG PACKAGE_BASEURL=https://download.zerotier.com/debian/bookworm/pool/main/z/zerotier-one 3 | ARG ARCH=amd64 4 | ARG VERSION=1.12.2 5 | RUN apt-get update -qq && apt-get install -qq --no-install-recommends -y ca-certificates curl 6 | RUN curl -sSL -o zerotier-one.deb "${PACKAGE_BASEURL}/zerotier-one_${VERSION}_${ARCH}.deb" 7 | 8 | FROM debian:bookworm 9 | RUN mkdir /app 10 | WORKDIR /app 11 | COPY --from=stage zerotier-one.deb . 12 | RUN apt-get update -qq && apt-get install -qq --no-install-recommends -y procps iptables openssl \ 13 | && apt-get clean \ 14 | && rm -rf /var/lib/apt/lists/* 15 | RUN dpkg -i zerotier-one.deb && rm -f zerotier-one.deb 16 | RUN echo "${VERSION}" >/etc/zerotier-version 17 | COPY entrypoint.sh entrypoint.sh 18 | RUN chmod 755 entrypoint.sh 19 | ENTRYPOINT ["/app/entrypoint.sh"] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ZeroTierBridge 2 | 3 | A container to provide out-of-the-box bridging functionality to a ZeroTier network. 4 | 5 | ## Running 6 | 7 | ### Prerequisites 8 | 9 | - Docker running as your logged in user (if `docker ps` runs then you're good, if not follow the link ->) - [Linux instructions here](https://docs.docker.com/engine/install/linux-postinstall/) 10 | 11 | ### ZeroTier UI Changes 12 | 13 | Once running, log into your ZeroTier interface and approve the new device. Click the wrench next to the name and select 'Allow Ethernet Bridging.' 14 | 15 | ![brave_RxG5EgQinY](https://user-images.githubusercontent.com/1135584/129230874-76f80345-5389-46f7-b892-0692f41be20b.png) 16 | 17 | You also need to add a static route into ZeroTier so that the traffic is routed correctly. Add this a bit larger than normal because of [longest prefix matching](https://en.wikipedia.org/wiki/Longest_prefix_match). 18 | 19 | ![brave_4wHd9zo193](https://user-images.githubusercontent.com/1135584/129230132-11bcfb72-7d9b-4b40-a4e5-72130c583077.png) 20 | 21 | ### Docker Compose 22 | 23 | **You need to edit the `ZT_NETWORKS` and `ARCH` variable in the `docker-compose.yml` file first to add your networks and make sure your acrhitecture is correct (see [this page](http://download.zerotier.com/debian/buster/pool/main/z/zerotier-one/) for examples, usually either amd64 or arm64)** 24 | 25 | Easiest way to bring up is via Docker Compose. Rename `docker-compose.yml.example` to `docker-compose.yml` and run `docker compose up -d`. 26 | 27 | If you want to disable bridging, set `ZT_BRIDGE=false`. This can be done after the initial networks have been joined (just change the environment variable in the `docker-compose.yml` file and run `), as the ZeroTier config persists but IPTables forwarding is done on each container startup. 28 | 29 | ### OG Docker 30 | 31 | `docker build -t zerotierbridge .` 32 | 33 | `docker run --privileged -e ZT_NETWORKS=NETWORK_1 NETWORK_2 -e ZT_BRIDGE=true zerotierbridge:latest` 34 | 35 | Add your network ID(s) into the `ZT_NETWORKS` argument, space separated. 36 | 37 | Disable bridging by passing `ZT_BRIDGE=false`. This can be done after the initial networks have been joined (just rebuild the container), as the ZeroTier config persists but IPTables forwarding is done on each container startup. 38 | 39 | #### Persistent Storage 40 | 41 | If you would like the container to retain the same ZeroTier client ID on reboot, attach a volume as per the below. 42 | 43 | `docker run --privileged -e ZT_NETWORKS=NETWORK_ID_HERE ZT_BRIDGE=true -v zt_config:/var/lib/zerotier-one/ zerotierbridge:latest` 44 | 45 | #### Caveat: Architecture 46 | 47 | If you need to run this on a device with different architecture (a raspberry pi, for instance), then just edit line 3 of the Dockerfile. 48 | 49 | If you were using a Raspberry Pi 4, you would change this to `ARCH=arm64` and the container will pull the correct ZeroTier installer. 50 | -------------------------------------------------------------------------------- /docker-compose.yml.example: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | zerotierbridge: 5 | container_name: zerotierbridge 6 | image: registry.dangerous.tech/dangeroustech/zerotierbridge 7 | restart: always 8 | privileged: true 9 | volumes: 10 | - zt_config:/var/lib/zerotier-one 11 | environment: 12 | - ZT_NETWORKS=NETWORK_ID_1 NETWORK_ID_2 NETWORK_ID_3 13 | - ZT_BRIDGE=true 14 | volumes: 15 | zt_config: -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | grepzt() { 4 | (find /proc -name exe | xargs -I{} readlink {}) 2>/dev/null | grep -q zerotier-one 5 | return $? 6 | } 7 | 8 | echo "starting zerotier" 9 | setsid /usr/sbin/zerotier-one & 10 | 11 | while ! grepzt 12 | do 13 | echo "zerotier hasn't started, waiting a second" 14 | sleep 1 15 | done 16 | 17 | # Set IPTables to allow NATting 18 | sysctl -w net.ipv4.ip_forward=1 > /dev/null 19 | 20 | echo "joining networks: $ZT_NETWORKS" 21 | 22 | for n in $ZT_NETWORKS 23 | do 24 | echo "joining $n" 25 | 26 | while ! zerotier-cli join "$n" 27 | do 28 | echo "joining $n failed; trying again in 1s" 29 | sleep 1 30 | done 31 | 32 | if [ "$ZT_BRIDGE" = "true" ] 33 | then 34 | echo "Configuring iptables on $(zerotier-cli get $n portDeviceName)" 35 | PHY_IFACE=eth0; ZT_IFACE=$(zerotier-cli get $n portDeviceName) 36 | 37 | iptables -t nat -A POSTROUTING -o $PHY_IFACE -j MASQUERADE 38 | iptables -t nat -A POSTROUTING -o $ZT_IFACE -j MASQUERADE 39 | iptables -A FORWARD -i $PHY_IFACE -o $ZT_IFACE -j ACCEPT 40 | iptables -A FORWARD -i $ZT_IFACE -o $PHY_IFACE -j ACCEPT 41 | fi 42 | done 43 | 44 | # Give ZT a second realise it's online 45 | sleep 10 46 | 47 | # Print Client Info 48 | echo "$(zerotier-cli info)" 49 | 50 | sleep infinity -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.1.2" 3 | } -------------------------------------------------------------------------------- /results.sarif: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.1.0", 3 | "$schema": "https://json.schemastore.org/sarif-2.1.0-rtm.5.json", 4 | "runs": [ 5 | { 6 | "tool": { 7 | "driver": { 8 | "name": "Grype", 9 | "version": "0.63.0", 10 | "informationUri": "https://github.com/anchore/grype" 11 | } 12 | }, 13 | "results": [] 14 | } 15 | ] 16 | } --------------------------------------------------------------------------------