mirror of
https://github.com/juanfont/headscale.git
synced 2024-11-30 02:43:05 +00:00
Resolve merge
This commit is contained in:
commit
189e883f91
10 changed files with 217 additions and 28 deletions
38
.github/renovate.json
vendored
Normal file
38
.github/renovate.json
vendored
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
"baseBranches": ["main"],
|
||||||
|
"username": "renovate-release",
|
||||||
|
"gitAuthor": "Renovate Bot <bot@renovateapp.com>",
|
||||||
|
"branchPrefix": "renovateaction/",
|
||||||
|
"onboarding": false,
|
||||||
|
"extends": ["config:base", ":rebaseStalePrs"],
|
||||||
|
"ignorePresets": [":prHourlyLimit2"],
|
||||||
|
"enabledManagers": ["dockerfile", "gomod", "github-actions","regex" ],
|
||||||
|
"includeForks": true,
|
||||||
|
"repositories": ["juanfont/headscale"],
|
||||||
|
"platform": "github",
|
||||||
|
"packageRules": [
|
||||||
|
{
|
||||||
|
"matchDatasources": ["go"],
|
||||||
|
"groupName": "Go modules",
|
||||||
|
"groupSlug": "gomod",
|
||||||
|
"separateMajorMinor": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matchDatasources": ["docker"],
|
||||||
|
"groupName": "Dockerfiles",
|
||||||
|
"groupSlug": "dockerfiles"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"regexManagers": [
|
||||||
|
{
|
||||||
|
"fileMatch": [
|
||||||
|
".github/workflows/.*.yml$"
|
||||||
|
],
|
||||||
|
"matchStrings": [
|
||||||
|
"\\s*go-version:\\s*\"?(?<currentValue>.*?)\"?\\n"
|
||||||
|
],
|
||||||
|
"datasourceTemplate": "golang-version",
|
||||||
|
"depNameTemplate": "actions/go-version"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
27
.github/workflows/renovatebot.yml
vendored
Normal file
27
.github/workflows/renovatebot.yml
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
---
|
||||||
|
name: Renovate
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "* * 5,20 * *" # Every 5th and 20th of the month
|
||||||
|
workflow_dispatch:
|
||||||
|
jobs:
|
||||||
|
renovate:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Get token
|
||||||
|
id: get_token
|
||||||
|
uses: machine-learning-apps/actions-app-token@master
|
||||||
|
with:
|
||||||
|
APP_PEM: ${{ secrets.RENOVATEBOT_SECRET }}
|
||||||
|
APP_ID: ${{ secrets.RENOVATEBOT_APP_ID }}
|
||||||
|
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2.0.0
|
||||||
|
|
||||||
|
- name: Self-hosted Renovate
|
||||||
|
uses: renovatebot/github-action@v31.81.3
|
||||||
|
with:
|
||||||
|
configurationFile: .github/renovate.json
|
||||||
|
token: "x-access-token:${{ steps.get_token.outputs.app_token }}"
|
||||||
|
# env:
|
||||||
|
# LOG_LEVEL: "debug"
|
|
@ -20,6 +20,10 @@ This is a part of aligning `headscale`'s behaviour with Tailscale's upstream beh
|
||||||
- Tags should now work correctly and adding a host to Headscale should now reload the rules.
|
- Tags should now work correctly and adding a host to Headscale should now reload the rules.
|
||||||
- The documentation have a [fictional example](docs/acls.md) that should cover some use cases of the ACLs features
|
- The documentation have a [fictional example](docs/acls.md) that should cover some use cases of the ACLs features
|
||||||
|
|
||||||
|
**Features**:
|
||||||
|
|
||||||
|
- Add support for configurable mTLS [docs](docs/tls.md#configuring-mutual-tls-authentication-mtls) [#297](https://github.com/juanfont/headscale/pull/297)
|
||||||
|
|
||||||
**Changes**:
|
**Changes**:
|
||||||
|
|
||||||
- Remove dependency on CGO (switch from CGO SQLite to pure Go) [#346](https://github.com/juanfont/headscale/pull/346)
|
- Remove dependency on CGO (switch from CGO SQLite to pure Go) [#346](https://github.com/juanfont/headscale/pull/346)
|
||||||
|
|
53
README.md
53
README.md
|
@ -47,6 +47,7 @@ If you would like to sponsor features, bugs or prioritisation, reach out to one
|
||||||
| ------- | ----------------------------------------------------------------------------------------------------------------- |
|
| ------- | ----------------------------------------------------------------------------------------------------------------- |
|
||||||
| Linux | Yes |
|
| Linux | Yes |
|
||||||
| OpenBSD | Yes |
|
| OpenBSD | Yes |
|
||||||
|
| FreeBSD | Yes |
|
||||||
| macOS | Yes (see `/apple` on your headscale for more information) |
|
| macOS | Yes (see `/apple` on your headscale for more information) |
|
||||||
| Windows | Yes [docs](./docs/windows-client.md) |
|
| Windows | Yes [docs](./docs/windows-client.md) |
|
||||||
| Android | [You need to compile the client yourself](https://github.com/juanfont/headscale/issues/58#issuecomment-885255270) |
|
| Android | [You need to compile the client yourself](https://github.com/juanfont/headscale/issues/58#issuecomment-885255270) |
|
||||||
|
@ -150,6 +151,13 @@ make build
|
||||||
<sub style="font-size:14px"><b>ohdearaugustin</b></sub>
|
<sub style="font-size:14px"><b>ohdearaugustin</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
|
<a href=https://github.com/restanrm>
|
||||||
|
<img src=https://avatars.githubusercontent.com/u/4344371?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Adrien Raffin-Caboisse/>
|
||||||
|
<br />
|
||||||
|
<sub style="font-size:14px"><b>Adrien Raffin-Caboisse</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
<a href=https://github.com/ItalyPaleAle>
|
<a href=https://github.com/ItalyPaleAle>
|
||||||
<img src=https://avatars.githubusercontent.com/u/43508?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Alessandro (Ale) Segala/>
|
<img src=https://avatars.githubusercontent.com/u/43508?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Alessandro (Ale) Segala/>
|
||||||
|
@ -157,6 +165,8 @@ make build
|
||||||
<sub style="font-size:14px"><b>Alessandro (Ale) Segala</b></sub>
|
<sub style="font-size:14px"><b>Alessandro (Ale) Segala</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
<a href=https://github.com/unreality>
|
<a href=https://github.com/unreality>
|
||||||
<img src=https://avatars.githubusercontent.com/u/352522?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=unreality/>
|
<img src=https://avatars.githubusercontent.com/u/352522?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=unreality/>
|
||||||
|
@ -164,8 +174,6 @@ make build
|
||||||
<sub style="font-size:14px"><b>unreality</b></sub>
|
<sub style="font-size:14px"><b>unreality</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
<a href=https://github.com/negbie>
|
<a href=https://github.com/negbie>
|
||||||
<img src=https://avatars.githubusercontent.com/u/20154956?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Eugen Biegler/>
|
<img src=https://avatars.githubusercontent.com/u/20154956?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Eugen Biegler/>
|
||||||
|
@ -201,6 +209,8 @@ make build
|
||||||
<sub style="font-size:14px"><b>Michael G.</b></sub>
|
<sub style="font-size:14px"><b>Michael G.</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
<a href=https://github.com/ptman>
|
<a href=https://github.com/ptman>
|
||||||
<img src=https://avatars.githubusercontent.com/u/24669?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Paul Tötterman/>
|
<img src=https://avatars.githubusercontent.com/u/24669?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Paul Tötterman/>
|
||||||
|
@ -208,8 +218,6 @@ make build
|
||||||
<sub style="font-size:14px"><b>Paul Tötterman</b></sub>
|
<sub style="font-size:14px"><b>Paul Tötterman</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
<a href=https://github.com/cmars>
|
<a href=https://github.com/cmars>
|
||||||
<img src=https://avatars.githubusercontent.com/u/23741?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Casey Marshall/>
|
<img src=https://avatars.githubusercontent.com/u/23741?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Casey Marshall/>
|
||||||
|
@ -245,6 +253,8 @@ make build
|
||||||
<sub style="font-size:14px"><b>thomas</b></sub>
|
<sub style="font-size:14px"><b>thomas</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
<a href=https://github.com/aberoham>
|
<a href=https://github.com/aberoham>
|
||||||
<img src=https://avatars.githubusercontent.com/u/586805?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Abraham Ingersoll/>
|
<img src=https://avatars.githubusercontent.com/u/586805?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Abraham Ingersoll/>
|
||||||
|
@ -252,15 +262,6 @@ make build
|
||||||
<sub style="font-size:14px"><b>Abraham Ingersoll</b></sub>
|
<sub style="font-size:14px"><b>Abraham Ingersoll</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
|
||||||
<a href=https://github.com/restanrm>
|
|
||||||
<img src=https://avatars.githubusercontent.com/u/4344371?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Adrien Raffin-Caboisse/>
|
|
||||||
<br />
|
|
||||||
<sub style="font-size:14px"><b>Adrien Raffin-Caboisse</b></sub>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
<a href=https://github.com/artemklevtsov>
|
<a href=https://github.com/artemklevtsov>
|
||||||
<img src=https://avatars.githubusercontent.com/u/603798?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Artem Klevtsov/>
|
<img src=https://avatars.githubusercontent.com/u/603798?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Artem Klevtsov/>
|
||||||
|
@ -305,6 +306,13 @@ make build
|
||||||
<sub style="font-size:14px"><b>JJGadgets</b></sub>
|
<sub style="font-size:14px"><b>JJGadgets</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
|
<a href=https://github.com/madjam002>
|
||||||
|
<img src=https://avatars.githubusercontent.com/u/679137?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Jamie Greeff/>
|
||||||
|
<br />
|
||||||
|
<sub style="font-size:14px"><b>Jamie Greeff</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
<a href=https://github.com/jimt>
|
<a href=https://github.com/jimt>
|
||||||
<img src=https://avatars.githubusercontent.com/u/180326?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Jim Tittsler/>
|
<img src=https://avatars.githubusercontent.com/u/180326?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Jim Tittsler/>
|
||||||
|
@ -333,6 +341,8 @@ make build
|
||||||
<sub style="font-size:14px"><b>Ryan Fowler</b></sub>
|
<sub style="font-size:14px"><b>Ryan Fowler</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
<a href=https://github.com/shaananc>
|
<a href=https://github.com/shaananc>
|
||||||
<img src=https://avatars.githubusercontent.com/u/2287839?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Shaanan Cohney/>
|
<img src=https://avatars.githubusercontent.com/u/2287839?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Shaanan Cohney/>
|
||||||
|
@ -340,8 +350,6 @@ make build
|
||||||
<sub style="font-size:14px"><b>Shaanan Cohney</b></sub>
|
<sub style="font-size:14px"><b>Shaanan Cohney</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
<a href=https://github.com/m-tanner-dev0>
|
<a href=https://github.com/m-tanner-dev0>
|
||||||
<img src=https://avatars.githubusercontent.com/u/97977342?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Tanner/>
|
<img src=https://avatars.githubusercontent.com/u/97977342?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Tanner/>
|
||||||
|
@ -377,6 +385,8 @@ make build
|
||||||
<sub style="font-size:14px"><b>Tjerk Woudsma</b></sub>
|
<sub style="font-size:14px"><b>Tjerk Woudsma</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
<a href=https://github.com/zekker6>
|
<a href=https://github.com/zekker6>
|
||||||
<img src=https://avatars.githubusercontent.com/u/1367798?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Zakhar Bessarab/>
|
<img src=https://avatars.githubusercontent.com/u/1367798?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Zakhar Bessarab/>
|
||||||
|
@ -384,8 +394,6 @@ make build
|
||||||
<sub style="font-size:14px"><b>Zakhar Bessarab</b></sub>
|
<sub style="font-size:14px"><b>Zakhar Bessarab</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
<a href=https://github.com/Bpazy>
|
<a href=https://github.com/Bpazy>
|
||||||
<img src=https://avatars.githubusercontent.com/u/9838749?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=ZiYuan/>
|
<img src=https://avatars.githubusercontent.com/u/9838749?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=ZiYuan/>
|
||||||
|
@ -421,6 +429,15 @@ make build
|
||||||
<sub style="font-size:14px"><b>lion24</b></sub>
|
<sub style="font-size:14px"><b>lion24</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
|
<a href=https://github.com/pernila>
|
||||||
|
<img src=https://avatars.githubusercontent.com/u/12460060?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=pernila/>
|
||||||
|
<br />
|
||||||
|
<sub style="font-size:14px"><b>pernila</b></sub>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
<a href=https://github.com/Wakeful-Cloud>
|
<a href=https://github.com/Wakeful-Cloud>
|
||||||
<img src=https://avatars.githubusercontent.com/u/38930607?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Wakeful-Cloud/>
|
<img src=https://avatars.githubusercontent.com/u/38930607?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=Wakeful-Cloud/>
|
||||||
|
@ -428,8 +445,6 @@ make build
|
||||||
<sub style="font-size:14px"><b>Wakeful-Cloud</b></sub>
|
<sub style="font-size:14px"><b>Wakeful-Cloud</b></sub>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
|
||||||
<a href=https://github.com/xpzouying>
|
<a href=https://github.com/xpzouying>
|
||||||
<img src=https://avatars.githubusercontent.com/u/3946563?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=zy/>
|
<img src=https://avatars.githubusercontent.com/u/3946563?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=zy/>
|
||||||
|
|
38
app.go
38
app.go
|
@ -62,6 +62,10 @@ const (
|
||||||
errUnsupportedLetsEncryptChallengeType = Error(
|
errUnsupportedLetsEncryptChallengeType = Error(
|
||||||
"unknown value for Lets Encrypt challenge type",
|
"unknown value for Lets Encrypt challenge type",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
DisabledClientAuth = "disabled"
|
||||||
|
RelaxedClientAuth = "relaxed"
|
||||||
|
EnforcedClientAuth = "enforced"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config contains the initial Headscale configuration.
|
// Config contains the initial Headscale configuration.
|
||||||
|
@ -90,8 +94,9 @@ type Config struct {
|
||||||
TLSLetsEncryptCacheDir string
|
TLSLetsEncryptCacheDir string
|
||||||
TLSLetsEncryptChallengeType string
|
TLSLetsEncryptChallengeType string
|
||||||
|
|
||||||
TLSCertPath string
|
TLSCertPath string
|
||||||
TLSKeyPath string
|
TLSKeyPath string
|
||||||
|
TLSClientAuthMode tls.ClientAuthType
|
||||||
|
|
||||||
ACMEURL string
|
ACMEURL string
|
||||||
ACMEEmail string
|
ACMEEmail string
|
||||||
|
@ -150,6 +155,27 @@ type Headscale struct {
|
||||||
requestedExpiryCache *cache.Cache
|
requestedExpiryCache *cache.Cache
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Look up the TLS constant relative to user-supplied TLS client
|
||||||
|
// authentication mode. If an unknown mode is supplied, the default
|
||||||
|
// value, tls.RequireAnyClientCert, is returned. The returned boolean
|
||||||
|
// indicates if the supplied mode was valid.
|
||||||
|
func LookupTLSClientAuthMode(mode string) (tls.ClientAuthType, bool) {
|
||||||
|
switch mode {
|
||||||
|
case DisabledClientAuth:
|
||||||
|
// Client cert is _not_ required.
|
||||||
|
return tls.NoClientCert, true
|
||||||
|
case RelaxedClientAuth:
|
||||||
|
// Client cert required, but _not verified_.
|
||||||
|
return tls.RequireAnyClientCert, true
|
||||||
|
case EnforcedClientAuth:
|
||||||
|
// Client cert is _required and verified_.
|
||||||
|
return tls.RequireAndVerifyClientCert, true
|
||||||
|
default:
|
||||||
|
// Return the default when an unknown value is supplied.
|
||||||
|
return tls.RequireAnyClientCert, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewHeadscale returns the Headscale app.
|
// NewHeadscale returns the Headscale app.
|
||||||
func NewHeadscale(cfg Config) (*Headscale, error) {
|
func NewHeadscale(cfg Config) (*Headscale, error) {
|
||||||
privKey, err := readOrCreatePrivateKey(cfg.PrivateKeyPath)
|
privKey, err := readOrCreatePrivateKey(cfg.PrivateKeyPath)
|
||||||
|
@ -676,12 +702,18 @@ func (h *Headscale) getTLSSettings() (*tls.Config, error) {
|
||||||
if !strings.HasPrefix(h.cfg.ServerURL, "https://") {
|
if !strings.HasPrefix(h.cfg.ServerURL, "https://") {
|
||||||
log.Warn().Msg("Listening with TLS but ServerURL does not start with https://")
|
log.Warn().Msg("Listening with TLS but ServerURL does not start with https://")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Info().Msg(fmt.Sprintf(
|
||||||
|
"Client authentication (mTLS) is \"%s\". See the docs to learn about configuring this setting.",
|
||||||
|
h.cfg.TLSClientAuthMode))
|
||||||
|
|
||||||
tlsConfig := &tls.Config{
|
tlsConfig := &tls.Config{
|
||||||
ClientAuth: tls.RequireAnyClientCert,
|
ClientAuth: h.cfg.TLSClientAuthMode,
|
||||||
NextProtos: []string{"http/1.1"},
|
NextProtos: []string{"http/1.1"},
|
||||||
Certificates: make([]tls.Certificate, 1),
|
Certificates: make([]tls.Certificate, 1),
|
||||||
MinVersion: tls.VersionTLS12,
|
MinVersion: tls.VersionTLS12,
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsConfig.Certificates[0], err = tls.LoadX509KeyPair(h.cfg.TLSCertPath, h.cfg.TLSKeyPath)
|
tlsConfig.Certificates[0], err = tls.LoadX509KeyPair(h.cfg.TLSCertPath, h.cfg.TLSKeyPath)
|
||||||
|
|
||||||
return tlsConfig, err
|
return tlsConfig, err
|
||||||
|
|
17
app_test.go
17
app_test.go
|
@ -65,3 +65,20 @@ func (s *Suite) ResetDB(c *check.C) {
|
||||||
}
|
}
|
||||||
app.db = db
|
app.db = db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enusre an error is returned when an invalid auth mode
|
||||||
|
// is supplied.
|
||||||
|
func (s *Suite) TestInvalidClientAuthMode(c *check.C) {
|
||||||
|
_, isValid := LookupTLSClientAuthMode("invalid")
|
||||||
|
c.Assert(isValid, check.Equals, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that all client auth modes return a nil error.
|
||||||
|
func (s *Suite) TestAuthModes(c *check.C) {
|
||||||
|
modes := []string{"disabled", "relaxed", "enforced"}
|
||||||
|
|
||||||
|
for _, v := range modes {
|
||||||
|
_, isValid := LookupTLSClientAuthMode(v)
|
||||||
|
c.Assert(isValid, check.Equals, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -50,6 +50,7 @@ func LoadConfig(path string) error {
|
||||||
|
|
||||||
viper.SetDefault("tls_letsencrypt_cache_dir", "/var/www/.cache")
|
viper.SetDefault("tls_letsencrypt_cache_dir", "/var/www/.cache")
|
||||||
viper.SetDefault("tls_letsencrypt_challenge_type", "HTTP-01")
|
viper.SetDefault("tls_letsencrypt_challenge_type", "HTTP-01")
|
||||||
|
viper.SetDefault("tls_client_auth_mode", "relaxed")
|
||||||
|
|
||||||
viper.SetDefault("log_level", "info")
|
viper.SetDefault("log_level", "info")
|
||||||
|
|
||||||
|
@ -92,6 +93,20 @@ func LoadConfig(path string) error {
|
||||||
!strings.HasPrefix(viper.GetString("server_url"), "https://") {
|
!strings.HasPrefix(viper.GetString("server_url"), "https://") {
|
||||||
errorText += "Fatal config error: server_url must start with https:// or http://\n"
|
errorText += "Fatal config error: server_url must start with https:// or http://\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, authModeValid := headscale.LookupTLSClientAuthMode(
|
||||||
|
viper.GetString("tls_client_auth_mode"),
|
||||||
|
)
|
||||||
|
|
||||||
|
if !authModeValid {
|
||||||
|
errorText += fmt.Sprintf(
|
||||||
|
"Invalid tls_client_auth_mode supplied: %s. Accepted values: %s, %s, %s.",
|
||||||
|
viper.GetString("tls_client_auth_mode"),
|
||||||
|
headscale.DisabledClientAuth,
|
||||||
|
headscale.RelaxedClientAuth,
|
||||||
|
headscale.EnforcedClientAuth)
|
||||||
|
}
|
||||||
|
|
||||||
if errorText != "" {
|
if errorText != "" {
|
||||||
//nolint
|
//nolint
|
||||||
return errors.New(strings.TrimSuffix(errorText, "\n"))
|
return errors.New(strings.TrimSuffix(errorText, "\n"))
|
||||||
|
@ -281,6 +296,10 @@ func getHeadscaleConfig() headscale.Config {
|
||||||
Msgf("'ip_prefixes' not configured, falling back to default: %v", prefixes)
|
Msgf("'ip_prefixes' not configured, falling back to default: %v", prefixes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tlsClientAuthMode, _ := headscale.LookupTLSClientAuthMode(
|
||||||
|
viper.GetString("tls_client_auth_mode"),
|
||||||
|
)
|
||||||
|
|
||||||
return headscale.Config{
|
return headscale.Config{
|
||||||
ServerURL: viper.GetString("server_url"),
|
ServerURL: viper.GetString("server_url"),
|
||||||
Addr: viper.GetString("listen_addr"),
|
Addr: viper.GetString("listen_addr"),
|
||||||
|
@ -312,8 +331,9 @@ func getHeadscaleConfig() headscale.Config {
|
||||||
),
|
),
|
||||||
TLSLetsEncryptChallengeType: viper.GetString("tls_letsencrypt_challenge_type"),
|
TLSLetsEncryptChallengeType: viper.GetString("tls_letsencrypt_challenge_type"),
|
||||||
|
|
||||||
TLSCertPath: absPath(viper.GetString("tls_cert_path")),
|
TLSCertPath: absPath(viper.GetString("tls_cert_path")),
|
||||||
TLSKeyPath: absPath(viper.GetString("tls_key_path")),
|
TLSKeyPath: absPath(viper.GetString("tls_key_path")),
|
||||||
|
TLSClientAuthMode: tlsClientAuthMode,
|
||||||
|
|
||||||
DNSConfig: dnsConfig,
|
DNSConfig: dnsConfig,
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,13 @@ acme_email: ""
|
||||||
# Domain name to request a TLS certificate for:
|
# Domain name to request a TLS certificate for:
|
||||||
tls_letsencrypt_hostname: ""
|
tls_letsencrypt_hostname: ""
|
||||||
|
|
||||||
|
# Client (Tailscale/Browser) authentication mode (mTLS)
|
||||||
|
# Acceptable values:
|
||||||
|
# - disabled: client authentication disabled
|
||||||
|
# - relaxed: client certificate is required but not verified
|
||||||
|
# - enforced: client certificate is required and verified
|
||||||
|
tls_client_auth_mode: relaxed
|
||||||
|
|
||||||
# Path to store certificates and metadata needed by
|
# Path to store certificates and metadata needed by
|
||||||
# letsencrypt
|
# letsencrypt
|
||||||
tls_letsencrypt_cache_dir: /var/lib/headscale/cache
|
tls_letsencrypt_cache_dir: /var/lib/headscale/cache
|
||||||
|
|
23
db.go
23
db.go
|
@ -2,6 +2,7 @@ package headscale
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/glebarez/sqlite"
|
"github.com/glebarez/sqlite"
|
||||||
"gorm.io/driver/postgres"
|
"gorm.io/driver/postgres"
|
||||||
|
@ -81,10 +82,24 @@ func (h *Headscale) openDB() (*gorm.DB, error) {
|
||||||
|
|
||||||
switch h.dbType {
|
switch h.dbType {
|
||||||
case Sqlite:
|
case Sqlite:
|
||||||
db, err = gorm.Open(sqlite.Open(h.dbString), &gorm.Config{
|
db, err = gorm.Open(
|
||||||
DisableForeignKeyConstraintWhenMigrating: true,
|
sqlite.Open(h.dbString+"?_synchronous=1&_journal_mode=WAL"),
|
||||||
Logger: log,
|
&gorm.Config{
|
||||||
})
|
DisableForeignKeyConstraintWhenMigrating: true,
|
||||||
|
Logger: log,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
db.Exec("PRAGMA foreign_keys=ON")
|
||||||
|
|
||||||
|
// The pure Go SQLite library does not handle locking in
|
||||||
|
// the same way as the C based one and we cant use the gorm
|
||||||
|
// connection pool as of 2022/02/23.
|
||||||
|
sqlDB, _ := db.DB()
|
||||||
|
sqlDB.SetMaxIdleConns(1)
|
||||||
|
sqlDB.SetMaxOpenConns(1)
|
||||||
|
sqlDB.SetConnMaxIdleTime(time.Hour)
|
||||||
|
|
||||||
case Postgres:
|
case Postgres:
|
||||||
db, err = gorm.Open(postgres.Open(h.dbString), &gorm.Config{
|
db, err = gorm.Open(postgres.Open(h.dbString), &gorm.Config{
|
||||||
DisableForeignKeyConstraintWhenMigrating: true,
|
DisableForeignKeyConstraintWhenMigrating: true,
|
||||||
|
|
14
docs/tls.md
14
docs/tls.md
|
@ -29,3 +29,17 @@ headscale can also be configured to expose its web service via TLS. To configure
|
||||||
tls_cert_path: ""
|
tls_cert_path: ""
|
||||||
tls_key_path: ""
|
tls_key_path: ""
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Configuring Mutual TLS Authentication (mTLS)
|
||||||
|
|
||||||
|
mTLS is a method by which an HTTPS server authenticates clients, e.g. Tailscale, using TLS certificates. This can be configured by applying one of the following values to the `tls_client_auth_mode` setting in the configuration file.
|
||||||
|
|
||||||
|
| Value | Behavior |
|
||||||
|
| ------------------- | ---------------------------------------------------------- |
|
||||||
|
| `disabled` | Disable mTLS. |
|
||||||
|
| `relaxed` (default) | A client certificate is required, but it is not verified. |
|
||||||
|
| `enforced` | Requires clients to supply a certificate that is verified. |
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
tls_client_auth_mode: ""
|
||||||
|
```
|
||||||
|
|
Loading…
Reference in a new issue