diff --git a/cert/source.go b/cert/source.go index 142acc97e..e44b1a44e 100644 --- a/cert/source.go +++ b/cert/source.go @@ -63,6 +63,7 @@ func NewSource(cfg config.CertSource) (Source, error) { ClientCAPath: cfg.ClientCAPath, CAUpgradeCN: cfg.CAUpgradeCN, Refresh: cfg.Refresh, + RenewToken: cfg.RenewToken, vaultToken: os.Getenv("VAULT_TOKEN"), }, nil diff --git a/cert/source_test.go b/cert/source_test.go index 234c48e53..b10b2569f 100644 --- a/cert/source_test.go +++ b/cert/source_test.go @@ -103,6 +103,7 @@ func TestNewSource(t *testing.T) { ClientCAPath: "clientca", CAUpgradeCN: "upgcn", Refresh: 3 * time.Second, + RenewToken: 60 * time.Second, }, }, } diff --git a/cert/vault_source.go b/cert/vault_source.go index 78c0e2ac4..e812e5662 100644 --- a/cert/vault_source.go +++ b/cert/vault_source.go @@ -27,6 +27,7 @@ type VaultSource struct { ClientCAPath string CAUpgradeCN string Refresh time.Duration + RenewToken time.Duration mu sync.Mutex token string // actual token @@ -131,9 +132,7 @@ func (s *VaultSource) load(path string) (pemBlocks map[string][]byte, err error) } // renew token - // TODO(fs): make configurable - const oneHour = 3600 - _, err = c.Auth().Token().RenewSelf(oneHour) + _, err = c.Auth().Token().RenewSelf(int(s.RenewToken / time.Second)) if err != nil { // TODO(fs): danger of filling up log since default refresh is 1s if !dropNotRenewableError { diff --git a/config/config.go b/config/config.go index 5050239f6..8201518db 100644 --- a/config/config.go +++ b/config/config.go @@ -24,6 +24,7 @@ type CertSource struct { ClientCAPath string CAUpgradeCN string Refresh time.Duration + RenewToken time.Duration Header http.Header } diff --git a/config/default.go b/config/default.go index 3e187d53a..0ad43814b 100644 --- a/config/default.go +++ b/config/default.go @@ -12,10 +12,12 @@ var defaultValues = struct { WriteTimeout time.Duration UIListenerValue string GZIPContentTypesValue string + RenewToken time.Duration }{ ListenerValue: []string{":9999"}, CertSourcesValue: []map[string]string{}, UIListenerValue: ":9998", + RenewToken: time.Hour, } var defaultConfig = &Config{ diff --git a/config/load.go b/config/load.go index d1e696ce8..702e4ab19 100644 --- a/config/load.go +++ b/config/load.go @@ -406,6 +406,12 @@ func parseCertSource(cfg map[string]string) (c CertSource, err error) { return CertSource{}, err } c.Refresh = d + case "renewtoken": + d, err := time.ParseDuration(v) + if err != nil { + return CertSource{}, err + } + c.RenewToken = d case "hdr": p := strings.SplitN(v, ": ", 2) if len(p) != 2 { @@ -432,5 +438,8 @@ func parseCertSource(cfg map[string]string) (c CertSource, err error) { if c.Type == "file" { c.Refresh = 0 } + if c.Type == "vault" && c.RenewToken == 0 { + c.RenewToken = defaultValues.RenewToken + } return } diff --git a/config/load_test.go b/config/load_test.go index af70f30d5..eab320d1d 100644 --- a/config/load_test.go +++ b/config/load_test.go @@ -133,13 +133,22 @@ func TestLoad(t *testing.T) { args: []string{"-proxy.addr", ":5555;cs=name", "-proxy.cs", "cs=name;type=vault;cert=value"}, cfg: func(cfg *Config) *Config { cfg.Listen = []Listen{Listen{Addr: ":5555", Proto: "https"}} - cfg.Listen[0].CertSource = CertSource{Name: "name", Type: "vault", CertPath: "value", Refresh: 3 * time.Second} + cfg.Listen[0].CertSource = CertSource{Name: "name", Type: "vault", CertPath: "value", Refresh: 3 * time.Second, RenewToken: time.Hour} + return cfg + }, + }, + { + desc: "-proxy.addr with vault cert source and custom token renew interval", + args: []string{"-proxy.addr", ":5555;cs=name", "-proxy.cs", "cs=name;type=vault;cert=value;renewtoken=30m"}, + cfg: func(cfg *Config) *Config { + cfg.Listen = []Listen{Listen{Addr: ":5555", Proto: "https"}} + cfg.Listen[0].CertSource = CertSource{Name: "name", Type: "vault", CertPath: "value", Refresh: 3 * time.Second, RenewToken: 30 * time.Minute} return cfg }, }, { desc: "-proxy.addr with cert source", - args: []string{"-proxy.addr", ":5555;cs=name;strictmatch=true", "-proxy.cs", "cs=name;type=path;cert=foo;clientca=bar;refresh=2s;hdr=a: b;caupgcn=furb"}, + args: []string{"-proxy.addr", ":5555;cs=name;strictmatch=true", "-proxy.cs", "cs=name;type=path;cert=foo;clientca=bar;refresh=2s;renewtoken=60s;hdr=a: b;caupgcn=furb"}, cfg: func(cfg *Config) *Config { cfg.Listen = []Listen{ Listen{ @@ -152,6 +161,7 @@ func TestLoad(t *testing.T) { CertPath: "foo", ClientCAPath: "bar", Refresh: 2 * time.Second, + RenewToken: 60 * time.Second, Header: http.Header{"A": []string{"b"}}, CAUpgradeCN: "furb", }, @@ -162,7 +172,7 @@ func TestLoad(t *testing.T) { }, { desc: "-proxy.addr with cert source with full options", - args: []string{"-proxy.addr", ":5555;cs=name;strictmatch=true;proto=https", "-proxy.cs", "cs=name;type=path;cert=foo;clientca=bar;refresh=2s;hdr=a: b;caupgcn=furb"}, + args: []string{"-proxy.addr", ":5555;cs=name;strictmatch=true;proto=https", "-proxy.cs", "cs=name;type=path;cert=foo;clientca=bar;refresh=2s;renewtoken=60s;hdr=a: b;caupgcn=furb"}, cfg: func(cfg *Config) *Config { cfg.Listen = []Listen{ Listen{ @@ -175,6 +185,7 @@ func TestLoad(t *testing.T) { CertPath: "foo", ClientCAPath: "bar", Refresh: 2 * time.Second, + RenewToken: 60 * time.Second, Header: http.Header{"A": []string{"b"}}, CAUpgradeCN: "furb", }, diff --git a/fabio.properties b/fabio.properties index 6abc7303e..a15fe9a30 100644 --- a/fabio.properties +++ b/fabio.properties @@ -113,6 +113,9 @@ # to prevent busy loops. To load the certificates only once and disable # automatic refreshing set 'refresh' to zero. # +# The 'renewtoken' option can be set to configure the token renewal +# interval. The default is one hour. +# # The path to vault must be provided in the VAULT_ADDR environment # variable. The token must be provided in the VAULT_TOKEN environment # variable.