diff --git a/CHANGELOG.md b/CHANGELOG.md
index fc17886f..fe706c45 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,7 @@
- Sanitise the node key passed to registration url [#823](https://github.com/juanfont/headscale/pull/823)
- Add support for generating pre-auth keys with tags [#767](https://github.com/juanfont/headscale/pull/767)
- Add support for evaluating `autoApprovers` ACL entries when a machine is registered [#763](https://github.com/juanfont/headscale/pull/763)
+- Add config flag to allow Headscale to start if OIDC provider is down [#829](https://github.com/juanfont/headscale/pull/829)
## 0.16.4 (2022-08-21)
diff --git a/README.md b/README.md
index a0586f1b..2752d093 100644
--- a/README.md
+++ b/README.md
@@ -195,6 +195,15 @@ make build
Jiang Zhu
+
-
+
- lion24
+ sharkonet
|
diff --git a/app.go b/app.go
index 59101be3..3f43d7a1 100644
--- a/app.go
+++ b/app.go
@@ -53,8 +53,10 @@ const (
)
ErrFailedPrivateKey = Error("failed to read or create private key")
- ErrFailedNoisePrivateKey = Error("failed to read or create Noise protocol private key")
- ErrSamePrivateKeys = Error("private key and noise private key are the same")
+ ErrFailedNoisePrivateKey = Error(
+ "failed to read or create Noise protocol private key",
+ )
+ ErrSamePrivateKeys = Error("private key and noise private key are the same")
)
const (
@@ -193,7 +195,11 @@ func NewHeadscale(cfg *Config) (*Headscale, error) {
if cfg.OIDC.Issuer != "" {
err = app.initOIDC()
if err != nil {
- return nil, err
+ if cfg.OIDC.OnlyStartIfOIDCIsAvailable {
+ return nil, err
+ } else {
+ log.Warn().Err(err).Msg("failed to set up OIDC provider, falling back to CLI based authentication")
+ }
}
}
@@ -448,16 +454,20 @@ func (h *Headscale) createRouter(grpcMux *runtime.ServeMux) *mux.Router {
router.HandleFunc("/health", h.HealthHandler).Methods(http.MethodGet)
router.HandleFunc("/key", h.KeyHandler).Methods(http.MethodGet)
router.HandleFunc("/register/{nkey}", h.RegisterWebAPI).Methods(http.MethodGet)
- router.HandleFunc("/machine/{mkey}/map", h.PollNetMapHandler).Methods(http.MethodPost)
+ router.HandleFunc("/machine/{mkey}/map", h.PollNetMapHandler).
+ Methods(http.MethodPost)
router.HandleFunc("/machine/{mkey}", h.RegistrationHandler).Methods(http.MethodPost)
router.HandleFunc("/oidc/register/{nkey}", h.RegisterOIDC).Methods(http.MethodGet)
router.HandleFunc("/oidc/callback", h.OIDCCallback).Methods(http.MethodGet)
router.HandleFunc("/apple", h.AppleConfigMessage).Methods(http.MethodGet)
- router.HandleFunc("/apple/{platform}", h.ApplePlatformConfig).Methods(http.MethodGet)
+ router.HandleFunc("/apple/{platform}", h.ApplePlatformConfig).
+ Methods(http.MethodGet)
router.HandleFunc("/windows", h.WindowsConfigMessage).Methods(http.MethodGet)
- router.HandleFunc("/windows/tailscale.reg", h.WindowsRegConfig).Methods(http.MethodGet)
+ router.HandleFunc("/windows/tailscale.reg", h.WindowsRegConfig).
+ Methods(http.MethodGet)
router.HandleFunc("/swagger", SwaggerUI).Methods(http.MethodGet)
- router.HandleFunc("/swagger/v1/openapiv2.json", SwaggerAPIv1).Methods(http.MethodGet)
+ router.HandleFunc("/swagger/v1/openapiv2.json", SwaggerAPIv1).
+ Methods(http.MethodGet)
if h.cfg.DERP.ServerEnabled {
router.HandleFunc("/derp", h.DERPHandler)
@@ -477,7 +487,8 @@ func (h *Headscale) createRouter(grpcMux *runtime.ServeMux) *mux.Router {
func (h *Headscale) createNoiseMux() *mux.Router {
router := mux.NewRouter()
- router.HandleFunc("/machine/register", h.NoiseRegistrationHandler).Methods(http.MethodPost)
+ router.HandleFunc("/machine/register", h.NoiseRegistrationHandler).
+ Methods(http.MethodPost)
router.HandleFunc("/machine/map", h.NoisePollNetMapHandler)
return router
@@ -827,9 +838,8 @@ func (h *Headscale) getTLSSettings() (*tls.Config, error) {
ReadTimeout: HTTPReadTimeout,
}
- err := server.ListenAndServe()
-
go func() {
+ err := server.ListenAndServe()
log.Fatal().
Caller().
Err(err).
diff --git a/config-example.yaml b/config-example.yaml
index 69672b24..72397c78 100644
--- a/config-example.yaml
+++ b/config-example.yaml
@@ -230,6 +230,7 @@ unix_socket_permission: "0770"
# help us test it.
# OpenID Connect
# oidc:
+# only_start_if_oidc_is_available: true
# issuer: "https://your-oidc.issuer.com/path"
# client_id: "your-oidc-client-id"
# client_secret: "your-oidc-client-secret"
diff --git a/config.go b/config.go
index b000c566..494356d8 100644
--- a/config.go
+++ b/config.go
@@ -90,14 +90,15 @@ type LetsEncryptConfig struct {
}
type OIDCConfig struct {
- Issuer string
- ClientID string
- ClientSecret string
- Scope []string
- ExtraParams map[string]string
- AllowedDomains []string
- AllowedUsers []string
- StripEmaildomain bool
+ OnlyStartIfOIDCIsAvailable bool
+ Issuer string
+ ClientID string
+ ClientSecret string
+ Scope []string
+ ExtraParams map[string]string
+ AllowedDomains []string
+ AllowedUsers []string
+ StripEmaildomain bool
}
type DERPConfig struct {
@@ -174,6 +175,7 @@ func LoadConfig(path string, isFile bool) error {
viper.SetDefault("oidc.scope", []string{oidc.ScopeOpenID, "profile", "email"})
viper.SetDefault("oidc.strip_email_domain", true)
+ viper.SetDefault("oidc.only_start_if_oidc_is_available", true)
viper.SetDefault("logtail.enabled", false)
viper.SetDefault("randomize_client_port", false)
@@ -559,6 +561,9 @@ func GetHeadscaleConfig() (*Config, error) {
UnixSocketPermission: GetFileMode("unix_socket_permission"),
OIDC: OIDCConfig{
+ OnlyStartIfOIDCIsAvailable: viper.GetBool(
+ "oidc.only_start_if_oidc_is_available",
+ ),
Issuer: viper.GetString("oidc.issuer"),
ClientID: viper.GetString("oidc.client_id"),
ClientSecret: viper.GetString("oidc.client_secret"),
diff --git a/flake.lock b/flake.lock
index 45b4c6d7..92184e8c 100644
--- a/flake.lock
+++ b/flake.lock
@@ -17,11 +17,11 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1662019588,
- "narHash": "sha256-oPEjHKGGVbBXqwwL+UjsveJzghWiWV0n9ogo1X6l4cw=",
+ "lastModified": 1664106353,
+ "narHash": "sha256-HMJP80+DSxFySpWyuxz5+iNozS3+dVt0b4n6YMIU5/8=",
"owner": "NixOS",
"repo": "nixpkgs",
- "rev": "2da64a81275b68fdad38af669afeda43d401e94b",
+ "rev": "79d3ca08920364759c63fd3eb562e99c0c17044a",
"type": "github"
},
"original": {
diff --git a/flake.nix b/flake.nix
index 7927221e..050fd747 100644
--- a/flake.nix
+++ b/flake.nix
@@ -6,163 +6,163 @@
flake-utils.url = "github:numtide/flake-utils";
};
- outputs = { self, nixpkgs, flake-utils, ... }:
- let
- headscaleVersion = if (self ? shortRev) then self.shortRev else "dev";
- in
+ outputs = {
+ self,
+ nixpkgs,
+ flake-utils,
+ ...
+ }: let
+ headscaleVersion =
+ if (self ? shortRev)
+ then self.shortRev
+ else "dev";
+ in
{
- overlay = final: prev:
- let
- pkgs = nixpkgs.legacyPackages.${prev.system};
- in
- rec {
- headscale =
- pkgs.buildGo119Module rec {
- pname = "headscale";
- version = headscaleVersion;
- src = pkgs.lib.cleanSource self;
+ overlay = _: prev: let
+ pkgs = nixpkgs.legacyPackages.${prev.system};
+ in rec {
+ headscale = pkgs.buildGo119Module rec {
+ pname = "headscale";
+ version = headscaleVersion;
+ src = pkgs.lib.cleanSource self;
- # When updating go.mod or go.sum, a new sha will need to be calculated,
- # update this if you have a mismatch after doing a change to thos files.
- vendorSha256 = "sha256-DosFCSiQ5FURbIrt4NcPGkExc84t2MGMqe9XLxNHdIM=";
+ # When updating go.mod or go.sum, a new sha will need to be calculated,
+ # update this if you have a mismatch after doing a change to thos files.
+ vendorSha256 = "sha256-DosFCSiQ5FURbIrt4NcPGkExc84t2MGMqe9XLxNHdIM=";
- ldflags = [ "-s" "-w" "-X github.com/juanfont/headscale/cmd/headscale/cli.Version=v${version}" ];
- };
-
- golines =
- pkgs.buildGoModule rec {
- pname = "golines";
- version = "0.9.0";
-
- src = pkgs.fetchFromGitHub {
- owner = "segmentio";
- repo = "golines";
- rev = "v${version}";
- sha256 = "sha256-BUXEg+4r9L/gqe4DhTlhN55P3jWt7ZyWFQycO6QePrw=";
- };
-
- vendorSha256 = "sha256-sEzWUeVk5GB0H41wrp12P8sBWRjg0FHUX6ABDEEBqK8=";
-
- nativeBuildInputs = [ pkgs.installShellFiles ];
- };
-
- golangci-lint = prev.golangci-lint.override {
- # Override https://github.com/NixOS/nixpkgs/pull/166801 which changed this
- # to buildGo118Module because it does not build on Darwin.
- inherit (prev) buildGoModule;
- };
-
- # golangci-lint =
- # pkgs.buildGo117Module rec {
- # pname = "golangci-lint";
- # version = "1.46.2";
- #
- # src = pkgs.fetchFromGitHub {
- # owner = "golangci";
- # repo = "golangci-lint";
- # rev = "v${version}";
- # sha256 = "sha256-7sDAwWz+qoB/ngeH35tsJ5FZUfAQvQsU6kU9rUHIHMk=";
- # };
- #
- # vendorSha256 = "sha256-w38OKN6HPoz37utG/2QSPMai55IRDXCIIymeMe6ogIU=";
- #
- # nativeBuildInputs = [ pkgs.installShellFiles ];
- # };
-
- protoc-gen-grpc-gateway =
- pkgs.buildGoModule rec {
- pname = "grpc-gateway";
- version = "2.8.0";
-
- src = pkgs.fetchFromGitHub {
- owner = "grpc-ecosystem";
- repo = "grpc-gateway";
- rev = "v${version}";
- sha256 = "sha256-8eBBBYJ+tBjB2fgPMX/ZlbN3eeS75e8TAZYOKXs6hcg=";
- };
-
- vendorSha256 = "sha256-AW2Gn/mlZyLMwF+NpK59eiOmQrYWW/9HPjbunYc9Ij4=";
-
- nativeBuildInputs = [ pkgs.installShellFiles ];
-
- subPackages = [ "protoc-gen-grpc-gateway" "protoc-gen-openapiv2" ];
- };
+ ldflags = ["-s" "-w" "-X github.com/juanfont/headscale/cmd/headscale/cli.Version=v${version}"];
};
- } // flake-utils.lib.eachDefaultSystem
- (system:
- let
- pkgs = import nixpkgs {
- overlays = [ self.overlay ];
- inherit system;
+
+ golines = pkgs.buildGoModule rec {
+ pname = "golines";
+ version = "0.9.0";
+
+ src = pkgs.fetchFromGitHub {
+ owner = "segmentio";
+ repo = "golines";
+ rev = "v${version}";
+ sha256 = "sha256-BUXEg+4r9L/gqe4DhTlhN55P3jWt7ZyWFQycO6QePrw=";
};
- buildDeps = with pkgs; [ git go_1_19 gnumake ];
- devDeps = with pkgs;
- buildDeps ++ [
+
+ vendorSha256 = "sha256-sEzWUeVk5GB0H41wrp12P8sBWRjg0FHUX6ABDEEBqK8=";
+
+ nativeBuildInputs = [pkgs.installShellFiles];
+ };
+
+ golangci-lint = prev.golangci-lint.override {
+ # Override https://github.com/NixOS/nixpkgs/pull/166801 which changed this
+ # to buildGo118Module because it does not build on Darwin.
+ inherit (prev) buildGoModule;
+ };
+
+ # golangci-lint =
+ # pkgs.buildGo117Module rec {
+ # pname = "golangci-lint";
+ # version = "1.46.2";
+ #
+ # src = pkgs.fetchFromGitHub {
+ # owner = "golangci";
+ # repo = "golangci-lint";
+ # rev = "v${version}";
+ # sha256 = "sha256-7sDAwWz+qoB/ngeH35tsJ5FZUfAQvQsU6kU9rUHIHMk=";
+ # };
+ #
+ # vendorSha256 = "sha256-w38OKN6HPoz37utG/2QSPMai55IRDXCIIymeMe6ogIU=";
+ #
+ # nativeBuildInputs = [ pkgs.installShellFiles ];
+ # };
+
+ protoc-gen-grpc-gateway = pkgs.buildGoModule rec {
+ pname = "grpc-gateway";
+ version = "2.8.0";
+
+ src = pkgs.fetchFromGitHub {
+ owner = "grpc-ecosystem";
+ repo = "grpc-gateway";
+ rev = "v${version}";
+ sha256 = "sha256-8eBBBYJ+tBjB2fgPMX/ZlbN3eeS75e8TAZYOKXs6hcg=";
+ };
+
+ vendorSha256 = "sha256-AW2Gn/mlZyLMwF+NpK59eiOmQrYWW/9HPjbunYc9Ij4=";
+
+ nativeBuildInputs = [pkgs.installShellFiles];
+
+ subPackages = ["protoc-gen-grpc-gateway" "protoc-gen-openapiv2"];
+ };
+ };
+ }
+ // flake-utils.lib.eachDefaultSystem
+ (system: let
+ pkgs = import nixpkgs {
+ overlays = [self.overlay];
+ inherit system;
+ };
+ buildDeps = with pkgs; [git go_1_19 gnumake];
+ devDeps = with pkgs;
+ buildDeps
+ ++ [
+ golangci-lint
+ golines
+ nodePackages.prettier
+
+ # Protobuf dependencies
+ protobuf
+ protoc-gen-go
+ protoc-gen-go-grpc
+ protoc-gen-grpc-gateway
+ buf
+ clang-tools # clang-format
+ ];
+
+ # Add entry to build a docker image with headscale
+ # caveat: only works on Linux
+ #
+ # Usage:
+ # nix build .#headscale-docker
+ # docker load < result
+ headscale-docker = pkgs.dockerTools.buildLayeredImage {
+ name = "headscale";
+ tag = headscaleVersion;
+ contents = [pkgs.headscale];
+ config.Entrypoint = [(pkgs.headscale + "/bin/headscale")];
+ };
+ in rec {
+ # `nix develop`
+ devShell = pkgs.mkShell {buildInputs = devDeps;};
+
+ # `nix build`
+ packages = with pkgs; {
+ inherit headscale;
+ inherit headscale-docker;
+ };
+
+ defaultPackage = pkgs.headscale;
+
+ # `nix run`
+ apps.headscale = flake-utils.lib.mkApp {
+ drv = packages.headscale;
+ };
+ defaultApp = apps.headscale;
+
+ checks = {
+ format =
+ pkgs.runCommand "check-format"
+ {
+ buildInputs = with pkgs; [
+ gnumake
+ nixpkgs-fmt
golangci-lint
- golines
nodePackages.prettier
-
- # Protobuf dependencies
- protobuf
- protoc-gen-go
- protoc-gen-go-grpc
- protoc-gen-grpc-gateway
- buf
- clang-tools # clang-format
+ golines
+ clang-tools
];
-
-
- # Add entry to build a docker image with headscale
- # caveat: only works on Linux
- #
- # Usage:
- # nix build .#headscale-docker
- # docker load < result
- headscale-docker = pkgs.dockerTools.buildLayeredImage {
- name = "headscale";
- tag = headscaleVersion;
- contents = [ pkgs.headscale ];
- config.Entrypoint = [ (pkgs.headscale + "/bin/headscale") ];
- };
- in
- rec {
- # `nix develop`
- devShell = pkgs.mkShell { buildInputs = devDeps; };
-
- # `nix build`
- packages = with pkgs; {
- inherit headscale;
- inherit headscale-docker;
- };
-
- defaultPackage = pkgs.headscale;
-
- # `nix run`
- apps.headscale = flake-utils.lib.mkApp {
- drv = packages.headscale;
- };
- defaultApp = apps.headscale;
-
- checks = {
- format = pkgs.runCommand "check-format"
- {
- buildInputs = with pkgs; [
- gnumake
- nixpkgs-fmt
- golangci-lint
- nodePackages.prettier
- golines
- clang-tools
- ];
- } ''
- ${pkgs.nixpkgs-fmt}/bin/nixpkgs-fmt ${./.}
- ${pkgs.golangci-lint}/bin/golangci-lint run --fix --timeout 10m
- ${pkgs.nodePackages.prettier}/bin/prettier --write '**/**.{ts,js,md,yaml,yml,sass,css,scss,html}'
- ${pkgs.golines}/bin/golines --max-len=88 --base-formatter=gofumpt -w ${./.}
- ${pkgs.clang-tools}/bin/clang-format -style="{BasedOnStyle: Google, IndentWidth: 4, AlignConsecutiveDeclarations: true, AlignConsecutiveAssignments: true, ColumnLimit: 0}" -i ${./.}
- '';
- };
-
-
- });
+ } ''
+ ${pkgs.nixpkgs-fmt}/bin/nixpkgs-fmt ${./.}
+ ${pkgs.golangci-lint}/bin/golangci-lint run --fix --timeout 10m
+ ${pkgs.nodePackages.prettier}/bin/prettier --write '**/**.{ts,js,md,yaml,yml,sass,css,scss,html}'
+ ${pkgs.golines}/bin/golines --max-len=88 --base-formatter=gofumpt -w ${./.}
+ ${pkgs.clang-tools}/bin/clang-format -style="{BasedOnStyle: Google, IndentWidth: 4, AlignConsecutiveDeclarations: true, AlignConsecutiveAssignments: true, ColumnLimit: 0}" -i ${./.}
+ '';
+ };
+ });
}
diff --git a/integration_test/etc/alt-config.dump.gold.yaml b/integration_test/etc/alt-config.dump.gold.yaml
index c9bd39b0..9df870fa 100644
--- a/integration_test/etc/alt-config.dump.gold.yaml
+++ b/integration_test/etc/alt-config.dump.gold.yaml
@@ -35,6 +35,7 @@ logtail:
enabled: false
metrics_listen_addr: 127.0.0.1:19090
oidc:
+ only_start_if_oidc_is_available: true
scope:
- openid
- profile
diff --git a/integration_test/etc/alt-env-config.dump.gold.yaml b/integration_test/etc/alt-env-config.dump.gold.yaml
index 4df4bf44..2fa8ef44 100644
--- a/integration_test/etc/alt-env-config.dump.gold.yaml
+++ b/integration_test/etc/alt-env-config.dump.gold.yaml
@@ -34,6 +34,7 @@ logtail:
enabled: false
metrics_listen_addr: 127.0.0.1:19090
oidc:
+ only_start_if_oidc_is_available: true
scope:
- openid
- profile
diff --git a/integration_test/etc/config.dump.gold.yaml b/integration_test/etc/config.dump.gold.yaml
index 158a1954..7bdd2c3e 100644
--- a/integration_test/etc/config.dump.gold.yaml
+++ b/integration_test/etc/config.dump.gold.yaml
@@ -35,6 +35,7 @@ logtail:
enabled: false
metrics_listen_addr: 127.0.0.1:9090
oidc:
+ only_start_if_oidc_is_available: true
scope:
- openid
- profile
diff --git a/protocol_common.go b/protocol_common.go
index b4c6223c..465279aa 100644
--- a/protocol_common.go
+++ b/protocol_common.go
@@ -483,7 +483,7 @@ func (h *Headscale) handleNewMachineCommon(
Bool("noise", machineKey.IsZero()).
Str("machine", registerRequest.Hostinfo.Hostname).
Msg("The node seems to be new, sending auth url")
- if h.cfg.OIDC.Issuer != "" {
+ if h.oauth2Config != nil {
resp.AuthURL = fmt.Sprintf(
"%s/oidc/register/%s",
strings.TrimSuffix(h.cfg.ServerURL, "/"),
@@ -716,7 +716,7 @@ func (h *Headscale) handleMachineExpiredCommon(
return
}
- if h.cfg.OIDC.Issuer != "" {
+ if h.oauth2Config != nil {
resp.AuthURL = fmt.Sprintf("%s/oidc/register/%s",
strings.TrimSuffix(h.cfg.ServerURL, "/"),
NodePublicKeyStripPrefix(registerRequest.NodeKey))
|