From f00a9cc1fb9024bef444b52c0bd09dbc2e0e6a76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arne=20J=C3=B8rgensen?= Date: Wed, 28 Aug 2024 16:15:39 +0200 Subject: [PATCH] Initial commit --- .github/dependabot.yml | 8 +++ .github/workflows/lint.yml | 32 +++++++++++ .github/workflows/test.yml | 21 +++++++ .yamllint | 17 ++++++ CODE_OF_CONDUCT.md | 77 ++++++++++++++++++++++++++ CONTRIBUTING.md | 40 ++++++++++++++ LICENSE.md | 22 ++++++++ READMD.md | 20 +++++++ action.yml | 27 +++++++++ vpn-down.mjs | 11 ++++ vpn-down.sh | 4 ++ vpn-up.mjs | 110 +++++++++++++++++++++++++++++++++++++ vpn-up.sh | 24 ++++++++ 13 files changed, 413 insertions(+) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/test.yml create mode 100644 .yamllint create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE.md create mode 100644 READMD.md create mode 100644 action.yml create mode 100644 vpn-down.mjs create mode 100755 vpn-down.sh create mode 100644 vpn-up.mjs create mode 100755 vpn-up.sh diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..f48c8be --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +--- +version: 2 +updates: + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: daily + timezone: Europe/Copenhagen diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..4ce61f6 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,32 @@ +--- +name: Lint +on: + - pull_request + - push + +permissions: + contents: read + pull-requests: write + +jobs: + actionlint: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - uses: reviewdog/action-actionlint@v1 + markdownlint: + name: markdown + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - name: Run markdownlint + uses: DavidAnson/markdownlint-cli2-action@v16 + yamllint: + name: Yamllint + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - name: Run Yamllint + uses: frenck/action-yamllint@v1.5.0 + with: + strict: true diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..87c3b23 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,21 @@ +--- +name: Test VPN +on: + - pull_request + - workflow_dispatch + +jobs: + test-vpn: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - uses: ./ + with: + server: ${{ vars.RELOAD_HQ_IP }} + psk: ${{ secrets.RELOAD_VPN_PSK }} + username: ${{ vars.RELOAD_VPN_USERNAME }} + password: ${{ secrets.RELOAD_VPN_PASSWORD }} + route: 104.18.0.0/15 + - name: Test VPN connection + run: | + [ "$(curl --silent https://canhazip.com)" == "${{ vars.RELOAD_HQ_IP }}" ] || exit 1 diff --git a/.yamllint b/.yamllint new file mode 100644 index 0000000..848aada --- /dev/null +++ b/.yamllint @@ -0,0 +1,17 @@ +--- + +extends: default + +rules: + indentation: + spaces: 2 + line-length: disable + truthy: + check-keys: false + # Allow Drupalism upper case bools. + allowed-values: ['true', 'false', 'TRUE', 'FALSE'] + braces: + min-spaces-inside: 1 + max-spaces-inside: 1 + min-spaces-inside-empty: 0 + max-spaces-inside-empty: 0 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..f1987c7 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,77 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to make participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies within all project spaces, and it also applies when +an individual is representing the project or its community in public spaces. +Examples of representing a project or community include using an official +project e-mail address, posting via an official social media account, or acting +as an appointed representative at an online or offline event. Representation of +a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at . All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 1.4, available at + + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..1fb2a90 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,40 @@ +# Developer Certificate of Origin + +```text +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +1 Letterman Drive +Suite D4700 +San Francisco, CA, 94129 + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with +   this project or the open source license(s) involved. +``` diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..21312ce --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,22 @@ +MIT License +=========== + +Copyright (c) 2020, 2021, 2022, 2023, 2024 Arne Jørgensen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/READMD.md b/READMD.md new file mode 100644 index 0000000..b30677d --- /dev/null +++ b/READMD.md @@ -0,0 +1,20 @@ +# Setup VPN connection in a GitHUb Actions workflow + +This action sets up a VPN connection in a GitHub Actions workflow. + +>[!NOTE] +> +> - This action is only supported on Linux runners. +> - This is designed to work with our Unifi VPN. Other VPNs may not work. + +Example setup: + +```yaml + - uses: reload/vpn-action@main + with: + server: ${{ vars.RELOAD_HQ_IP }} + psk: ${{ secrets.RELOAD_VPN_PSK }} + username: ${{ vars.RELOAD_VPN_USERNAME }} + password: ${{ secrets.RELOAD_VPN_PASSWORD }} + route: 94.23.123.122 # platform.sh FR-3 pr sites +``` diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..202e13c --- /dev/null +++ b/action.yml @@ -0,0 +1,27 @@ +--- +name: 'Setup VPN connection' +description: 'Connect Github Actions to VPN' +author: 'Arne Jørgensen' +branding: + color: green + icon: globe +inputs: + server: + required: true + description: 'VPN server' + psk: + required: true + description: 'VPN pre-shared key' + username: + required: true + description: 'VPN username' + password: + required: true + description: 'VPN password' + route: + required: true + description: 'VPN route' +runs: + using: 'node20' + main: 'vpn-up.mjs' + post: 'vpn-down.mjs' diff --git a/vpn-down.mjs b/vpn-down.mjs new file mode 100644 index 0000000..87b6e2a --- /dev/null +++ b/vpn-down.mjs @@ -0,0 +1,11 @@ +// -*- javascript -*- +// Config based on https://github.com/jabas06/l2tp-ipsec-vpn-client + +import { fileURLToPath } from "url"; +import path from "path"; +import { spawn } from "child_process"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +spawn("sudo", [`${__dirname}/vpn-down.sh`], { stdio: "inherit" }); diff --git a/vpn-down.sh b/vpn-down.sh new file mode 100755 index 0000000..9b9bdad --- /dev/null +++ b/vpn-down.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +bash -c 'echo "d myVPN" > /var/run/xl2tpd/l2tp-control' +ipsec down L2TP-PSK diff --git a/vpn-up.mjs b/vpn-up.mjs new file mode 100644 index 0000000..43b9ce2 --- /dev/null +++ b/vpn-up.mjs @@ -0,0 +1,110 @@ +// -*- javascript -*- +// Config based on https://github.com/jabas06/l2tp-ipsec-vpn-client + +import { fileURLToPath } from "url"; +import path from "path"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +import { writeFile } from "fs"; +import { spawn } from "child_process"; + +const server = process.env.INPUT_SERVER || ""; +const username = process.env.INPUT_USERNAME || ""; +const password = process.env.INPUT_PASSWORD || ""; +const psk = process.env.INPUT_PSK || ""; +const route = process.env.INPUT_ROUTE || ""; + +let ipsecConf = "ipsec.conf"; +let ipsecSecrets = "ipsec.secrets"; +let xl2tpdConf = "xl2tpd.conf"; +let optionsL2tpdClient = "options.l2tpd.client"; + +async function vpn() { + const ipsecConfContent = ` +config setup + +conn %default + ikelifetime=60m + keylife=20m + rekeymargin=3m + keyingtries=1 + keyexchange=ikev1 + authby=secret + ike=3des-sha1-modp1024 + esp=3des-sha1 + +conn L2TP-PSK + keyexchange=ikev1 + left=%defaultroute + auto=add + authby=secret + type=transport + leftprotoport=17/1701 + rightprotoport=17/1701 + right=${server} +`; + + await writeFile(ipsecConf, ipsecConfContent.trim(), (err) => { + if (err) throw err; + }); + + const ipsecSecretsContent = ` +${server} : PSK "${psk}" +`; + + await writeFile(ipsecSecrets, ipsecSecretsContent.trim(), (err) => { + if (err) throw err; + }); + + const xl2tpdConfigContent = ` +[lac myVPN] +lns = ${server} +ppp debug = yes +pppoptfile = /etc/ppp/options.l2tpd.client +length bit = yes +`; + + await writeFile(xl2tpdConf, xl2tpdConfigContent.trim(), (err) => { + if (err) throw err; + }); + + const optionsL2tpdClientContent = ` +ipcp-accept-local +ipcp-accept-remote +refuse-eap +require-mschap-v2 +noccp +noauth +logfile /var/log/xl2tpd.log +idle 1800 +mtu 1410 +mru 1410 +defaultroute +usepeerdns +debug +connect-delay 5000 +name ${username} +password ${password} +`; + + await writeFile( + optionsL2tpdClient, + optionsL2tpdClientContent.trim(), + (err) => { + if (err) throw err; + }, + ); + + const routeScriptContent = ` +ip route add ${route} via 10.255.255.0 dev ppp0 +`; + await writeFile("route.sh", routeScriptContent.trim(), (err) => { + if (err) throw err; + }); +} + +await vpn(); + +spawn("sudo", [`${__dirname}/vpn-up.sh`], { stdio: "inherit" }); diff --git a/vpn-up.sh b/vpn-up.sh new file mode 100755 index 0000000..fbb0fd8 --- /dev/null +++ b/vpn-up.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +apt-get --quiet --assume-yes update +apt-get --quiet --assume-yes install strongswan xl2tpd + +mkdir -p /var/run/xl2tpd +mkdir -p /etc/xl2tpd +mkdir -p /etc/ppp + +cp ipsec.conf /etc/ipsec.conf +cp ipsec.secrets /etc/ipsec.secrets +cp xl2tpd.conf /etc/xl2tpd/xl2tpd.conf +cp options.l2tpd.client /etc/ppp/options.l2tpd.client + +touch /var/run/xl2tpd/l2tp-control +systemctl restart strongswan-starter xl2tpd ipsec +sleep 8 +ipsec up L2TP-PSK +sleep 8 +bash -c 'echo "c myVPN" > /var/run/xl2tpd/l2tp-control' +sleep 8 +ifconfig + +chmod +x route.sh && ./route.sh