From 3be74bb2758db2beff604eb9f999f73ff6c4edec Mon Sep 17 00:00:00 2001 From: NicoMen Date: Tue, 10 Apr 2018 10:52:04 +0200 Subject: [PATCH] Fix acme.json file automatic creation --- acme/acme.go | 4 +- acme/localStore.go | 2 +- integration/acme_test.go | 2 + integration/fixtures/acme/acme_http01.toml | 2 +- .../fixtures/acme/acme_http01_web.toml | 2 +- integration/fixtures/acme/acme_provided.toml | 2 +- .../fixtures/acme/acme_provided_dynamic.toml | 2 +- .../fixtures/acme/no_challenge_acme.toml | 2 +- integration/fixtures/acme/wrong_acme.toml | 2 +- integration/fixtures/provideracme/acme.toml | 2 +- .../fixtures/provideracme/acme_insan.toml | 2 +- .../fixtures/provideracme/acme_onhost.toml | 2 +- provider/acme/local_store.go | 45 +++++++++++-------- .../acme/local_store_unix.go | 11 ++++- .../acme/local_store_windows.go | 11 ++++- provider/acme/provider.go | 6 +-- 16 files changed, 61 insertions(+), 38 deletions(-) rename acme/localStore_unix.go => provider/acme/local_store_unix.go (61%) rename acme/localStore_windows.go => provider/acme/local_store_windows.go (54%) diff --git a/acme/acme.go b/acme/acme.go index 74d71d1c7..623fe72d5 100644 --- a/acme/acme.go +++ b/acme/acme.go @@ -46,9 +46,9 @@ type ACME struct { OnHostRule bool `description:"Enable certificate generation on frontends Host rules."` CAServer string `description:"CA server to use."` EntryPoint string `description:"Entrypoint to proxy acme challenge to."` - DNSChallenge *acmeprovider.DNSChallenge `description:"Activate DNS-01 Challenge"` + DNSChallenge *acmeprovider.DNSChallenge `description:"Activate DNS-02 Challenge"` HTTPChallenge *acmeprovider.HTTPChallenge `description:"Activate HTTP-01 Challenge"` - DNSProvider string `description:"Activate DNS-01 Challenge (Deprecated)"` // deprecated + DNSProvider string `description:"Activate DNS-02 Challenge (Deprecated)"` // deprecated DelayDontCheckDNS flaeg.Duration `description:"Assume DNS propagates after a delay in seconds rather than finding and querying nameservers."` // deprecated ACMELogging bool `description:"Enable debug logging of ACME actions."` client *acme.Client diff --git a/acme/localStore.go b/acme/localStore.go index bb4c1bdc1..e3a3fdd4b 100644 --- a/acme/localStore.go +++ b/acme/localStore.go @@ -26,7 +26,7 @@ func NewLocalStore(file string) *LocalStore { func (s *LocalStore) Get() (*Account, error) { account := &Account{} - hasData, err := checkFile(s.file) + hasData, err := acme.CheckFile(s.file) if err != nil { return nil, err } diff --git a/integration/acme_test.go b/integration/acme_test.go index 73ae9cf8f..395fc7f6c 100644 --- a/integration/acme_test.go +++ b/integration/acme_test.go @@ -195,6 +195,8 @@ func (s *AcmeSuite) retrieveAcmeCertificate(c *check.C, testCase AcmeTestCase) { err := cmd.Start() c.Assert(err, checker.IsNil) defer cmd.Process.Kill() + // A real file is needed to have the right mode on acme.json file + defer os.Remove("/tmp/acme.json") backend := startTestServer("9010", http.StatusOK) defer backend.Close() diff --git a/integration/fixtures/acme/acme_http01.toml b/integration/fixtures/acme/acme_http01.toml index f66dab90b..917417bd6 100644 --- a/integration/fixtures/acme/acme_http01.toml +++ b/integration/fixtures/acme/acme_http01.toml @@ -12,7 +12,7 @@ defaultEntryPoints = ["http", "https"] [acme] email = "test@traefik.io" -storage = "/dev/null" +storage = "/tmp/acme.json" entryPoint = "https" onDemand = {{.OnDemand}} onHostRule = {{.OnHostRule}} diff --git a/integration/fixtures/acme/acme_http01_web.toml b/integration/fixtures/acme/acme_http01_web.toml index 42635d794..81bedc5be 100644 --- a/integration/fixtures/acme/acme_http01_web.toml +++ b/integration/fixtures/acme/acme_http01_web.toml @@ -11,7 +11,7 @@ defaultEntryPoints = ["http", "https"] [acme] email = "test@traefik.io" -storage = "/dev/null" +storage = "/tmp/acme.json" entryPoint = "https" onDemand = {{.OnDemand}} onHostRule = {{.OnHostRule}} diff --git a/integration/fixtures/acme/acme_provided.toml b/integration/fixtures/acme/acme_provided.toml index 55f16a946..2b4a90885 100644 --- a/integration/fixtures/acme/acme_provided.toml +++ b/integration/fixtures/acme/acme_provided.toml @@ -14,7 +14,7 @@ defaultEntryPoints = ["http", "https"] [acme] email = "test@traefik.io" -storage = "/dev/null" +storage = "/tmp/acme.json" entryPoint = "https" onDemand = {{.OnDemand}} onHostRule = {{.OnHostRule}} diff --git a/integration/fixtures/acme/acme_provided_dynamic.toml b/integration/fixtures/acme/acme_provided_dynamic.toml index eace65acb..552b840d3 100644 --- a/integration/fixtures/acme/acme_provided_dynamic.toml +++ b/integration/fixtures/acme/acme_provided_dynamic.toml @@ -12,7 +12,7 @@ defaultEntryPoints = ["http", "https"] [acme] email = "test@traefik.io" -storage = "/dev/null" +storage = "/tmp/acme.json" entryPoint = "https" onDemand = {{.OnDemand}} onHostRule = {{.OnHostRule}} diff --git a/integration/fixtures/acme/no_challenge_acme.toml b/integration/fixtures/acme/no_challenge_acme.toml index f26dc7f4f..7b855f214 100644 --- a/integration/fixtures/acme/no_challenge_acme.toml +++ b/integration/fixtures/acme/no_challenge_acme.toml @@ -14,7 +14,7 @@ defaultEntryPoints = ["http", "https"] [acme] email = "test@traefik.io" -storage = "/dev/null" +storage = "/tmp/acme.json" entryPoint = "https" onHostRule = true caServer = "http://{{.BoulderHost}}:4001/directory" diff --git a/integration/fixtures/acme/wrong_acme.toml b/integration/fixtures/acme/wrong_acme.toml index 0dbfd5c10..35f8ad004 100644 --- a/integration/fixtures/acme/wrong_acme.toml +++ b/integration/fixtures/acme/wrong_acme.toml @@ -14,7 +14,7 @@ defaultEntryPoints = ["http", "https"] [acme] email = "test@traefik.io" -storage = "/dev/null" +storage = "/tmp/acme.json" entryPoint = "https" onHostRule = true caServer = "http://wrongurl:4001/directory" diff --git a/integration/fixtures/provideracme/acme.toml b/integration/fixtures/provideracme/acme.toml index dabaef374..4b318b3d2 100644 --- a/integration/fixtures/provideracme/acme.toml +++ b/integration/fixtures/provideracme/acme.toml @@ -12,7 +12,7 @@ defaultEntryPoints = ["http", "https"] [acme] email = "test@traefik.io" -storage = "/dev/null" +storage = "/tmp/acme.json" entryPoint = "https" onDemand = {{.OnDemand}} onHostRule = {{.OnHostRule}} diff --git a/integration/fixtures/provideracme/acme_insan.toml b/integration/fixtures/provideracme/acme_insan.toml index 703cff9b1..060d63f17 100644 --- a/integration/fixtures/provideracme/acme_insan.toml +++ b/integration/fixtures/provideracme/acme_insan.toml @@ -12,7 +12,7 @@ defaultEntryPoints = ["http", "https"] [acme] email = "test@traefik.io" -storage = "/dev/null" +storage = "/tmp/acme.json" entryPoint = "https" onDemand = false onHostRule = false diff --git a/integration/fixtures/provideracme/acme_onhost.toml b/integration/fixtures/provideracme/acme_onhost.toml index fc7d6ee7d..6567e6cce 100644 --- a/integration/fixtures/provideracme/acme_onhost.toml +++ b/integration/fixtures/provideracme/acme_onhost.toml @@ -12,7 +12,7 @@ defaultEntryPoints = ["http", "https"] [acme] email = "test@traefik.io" -storage = "/dev/null" +storage = "/tmp/acme.json" entryPoint = "https" onDemand = {{.OnDemand}} onHostRule = {{.OnHostRule}} diff --git a/provider/acme/local_store.go b/provider/acme/local_store.go index 4156cd965..4d638d001 100644 --- a/provider/acme/local_store.go +++ b/provider/acme/local_store.go @@ -16,7 +16,7 @@ var _ Store = (*LocalStore)(nil) type LocalStore struct { filename string storedData *StoredData - SaveDataChan chan *StoredData + SaveDataChan chan *StoredData `json:"-"` } // NewLocalStore initializes a new LocalStore with a file name @@ -30,31 +30,38 @@ func (s *LocalStore) get() (*StoredData, error) { if s.storedData == nil { s.storedData = &StoredData{HTTPChallenges: make(map[string]map[string][]byte)} - f, err := os.Open(s.filename) - if err != nil { - return nil, err - } - defer f.Close() - - file, err := ioutil.ReadAll(f) + hasData, err := CheckFile(s.filename) if err != nil { return nil, err } - if len(file) > 0 { - if err := json.Unmarshal(file, s.storedData); err != nil { - return nil, err - } - } - // Check if ACME Account is in ACME V1 format - if s.storedData.Account != nil && s.storedData.Account.Registration != nil { - isOldRegistration, err := regexp.MatchString(RegistrationURLPathV1Regexp, s.storedData.Account.Registration.URI) + if hasData { + f, err := os.Open(s.filename) if err != nil { return nil, err } - if isOldRegistration { - s.storedData.Account = nil - s.SaveDataChan <- s.storedData + defer f.Close() + + file, err := ioutil.ReadAll(f) + if err != nil { + return nil, err + } + + if len(file) > 0 { + if err := json.Unmarshal(file, s.storedData); err != nil { + return nil, err + } + } + // Check if ACME Account is in ACME V1 format + if s.storedData.Account != nil && s.storedData.Account.Registration != nil { + isOldRegistration, err := regexp.MatchString(RegistrationURLPathV1Regexp, s.storedData.Account.Registration.URI) + if err != nil { + return nil, err + } + if isOldRegistration { + s.storedData.Account = nil + s.SaveDataChan <- s.storedData + } } } } diff --git a/acme/localStore_unix.go b/provider/acme/local_store_unix.go similarity index 61% rename from acme/localStore_unix.go rename to provider/acme/local_store_unix.go index a0d7e1a13..0dbb787be 100644 --- a/acme/localStore_unix.go +++ b/provider/acme/local_store_unix.go @@ -7,10 +7,17 @@ import ( "os" ) -// Check file permissions and content size -func checkFile(name string) (bool, error) { +// CheckFile checks file permissions and content size +func CheckFile(name string) (bool, error) { f, err := os.Open(name) if err != nil { + if os.IsNotExist(err) { + f, err = os.Create(name) + if err != nil { + return false, err + } + return false, f.Chmod(0600) + } return false, err } defer f.Close() diff --git a/acme/localStore_windows.go b/provider/acme/local_store_windows.go similarity index 54% rename from acme/localStore_windows.go rename to provider/acme/local_store_windows.go index 06df0cc5b..1804578a3 100644 --- a/acme/localStore_windows.go +++ b/provider/acme/local_store_windows.go @@ -2,11 +2,18 @@ package acme import "os" -// Check file content size +// CheckFile checks file content size // Do not check file permissions on Windows right now -func checkFile(name string) (bool, error) { +func CheckFile(name string) (bool, error) { f, err := os.Open(name) if err != nil { + if os.IsNotExist(err) { + f, err = os.Create(name) + if err != nil { + return false, err + } + return false, f.Chmod(0600) + } return false, err } defer f.Close() diff --git a/provider/acme/provider.go b/provider/acme/provider.go index b3029de9d..f23b030da 100644 --- a/provider/acme/provider.go +++ b/provider/acme/provider.go @@ -42,7 +42,7 @@ type Configuration struct { EntryPoint string `description:"EntryPoint to use."` OnHostRule bool `description:"Enable certificate generation on frontends Host rules."` OnDemand bool `description:"Enable on demand certificate generation. This will request a certificate from Let's Encrypt during the first TLS handshake for a hostname that does not yet have a certificate."` //deprecated - DNSChallenge *DNSChallenge `description:"Activate DNS-01 Challenge"` + DNSChallenge *DNSChallenge `description:"Activate DNS-02 Challenge"` HTTPChallenge *HTTPChallenge `description:"Activate HTTP-01 Challenge"` Domains []types.Domain `description:"CN and SANs (alternative domains) to each main domain using format: --acme.domains='main.com,san1.com,san2.com' --acme.domains='*.main.net'. No SANs for wildcards domain. Wildcard domains only accepted with DNSChallenge"` } @@ -72,7 +72,7 @@ type Certificate struct { // DNSChallenge contains DNS challenge Configuration type DNSChallenge struct { - Provider string `description:"Use a DNS-01 based challenge provider rather than HTTPS."` + Provider string `description:"Use a DNS-02 based challenge provider rather than HTTPS."` DelayBeforeCheck flaeg.Duration `description:"Assume DNS propagates after a delay in seconds rather than finding and querying nameservers."` } @@ -116,7 +116,7 @@ func (p *Provider) init() error { p.certificates, err = p.Store.GetCertificates() if err != nil { - return fmt.Errorf("unable to get ACME account : %v", err) + return fmt.Errorf("unable to get ACME certificates : %v", err) } p.watchCertificate()