diff --git a/directives.go b/directives.go index 74e326d..8e4d4af 100644 --- a/directives.go +++ b/directives.go @@ -5,6 +5,8 @@ import ( "fmt" "net" "net/url" + "os" + "os/exec" "strings" "git.sr.ht/~emersion/go-scfg" @@ -161,10 +163,46 @@ func parseTLS(srv *Server, d *scfg.Directive) error { } srv.ACMEManager.Email = email case "on_demand": - srv.ACMEConfig.OnDemand = &certmagic.OnDemandConfig{} + if err := parseTLSOnDemand(srv, child); err != nil { + return err + } default: return fmt.Errorf("unknown %q directive", child.Name) } } return nil } + +func parseTLSOnDemand(srv *Server, d *scfg.Directive) error { + if srv.ACMEConfig.OnDemand == nil { + srv.ACMEConfig.OnDemand = &certmagic.OnDemandConfig{} + } + + for _, child := range d.Children { + switch child.Name { + case "validate_command": + var cmdName string + if err := child.ParseParams(&cmdName); err != nil { + return err + } + decisionFunc := srv.ACMEConfig.OnDemand.DecisionFunc + srv.ACMEConfig.OnDemand.DecisionFunc = func(name string) error { + if decisionFunc != nil { + if err := decisionFunc(name); err != nil { + return err + } + } + cmd := exec.Command(cmdName, child.Params[1:]...) + cmd.Env = append(os.Environ(), "TLSTUNNEL_NAME="+name) + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to validate domain %q with command %q: %v", name, cmdName, err) + } + return nil + } + default: + return fmt.Errorf("unknown %q directive", child.Name) + } + } + + return nil +} diff --git a/tlstunnel.1.scd b/tlstunnel.1.scd index 7f35fcf..1cdf733 100644 --- a/tlstunnel.1.scd +++ b/tlstunnel.1.scd @@ -95,7 +95,7 @@ The following directives are supported: The email address to use when creating or selecting an existing ACME server account - *on_demand* + *on_demand* { ... } Enable on-demand TLS. When enabled, a TLS handshake may trigger maintenance for the relevant @@ -104,6 +104,18 @@ The following directives are supported: existing certificate is available, the certificate is renewed in the background if necessary. + Warning: to prevent abuse, you should specify a _validate_command_ + sub-directive. + + The on_demand directive supports the following optional sub-directives: + + *validate_command* command [arguments...] + Command to run before an on-demand certificate is obtained. If the + command returns a non-zero exit status, the request is denied. + + The environment will contain a *TLSTUNNEL_NAME* variable with the + domain name to be validated. + # FILES _/etc/tlstunnel/config_