mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2025-10-06 03:46:34 +08:00
CHORE: remove unused module pkg/acme (get-certs) (#3667)
This commit is contained in:
parent
f8252436c5
commit
a8a3ea73ba
8 changed files with 0 additions and 796 deletions
14
go.mod
14
go.mod
|
@ -34,7 +34,6 @@ require (
|
|||
github.com/go-gandi/go-gandi v0.7.0
|
||||
github.com/gobwas/glob v0.2.4-0.20181002190808-e7a84e9525fe
|
||||
github.com/gopherjs/jquery v0.0.0-20191017083323-73f4c7416038
|
||||
github.com/hashicorp/vault/api v1.20.0
|
||||
github.com/jinzhu/copier v0.4.0
|
||||
github.com/miekg/dns v1.1.67
|
||||
github.com/mittwald/go-powerdns v0.6.7
|
||||
|
@ -65,7 +64,6 @@ require (
|
|||
github.com/failsafe-go/failsafe-go v0.6.9
|
||||
github.com/fatih/color v1.18.0
|
||||
github.com/fbiville/markdown-table-formatter v0.3.0
|
||||
github.com/go-acme/lego/v4 v4.24.0
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.158
|
||||
|
@ -99,16 +97,13 @@ require (
|
|||
github.com/aws/aws-sdk-go-v2/service/sts v1.34.0 // indirect
|
||||
github.com/aws/smithy-go v1.22.4 // indirect
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/deepmap/oapi-codegen v1.9.1 // indirect
|
||||
github.com/fatih/structs v1.1.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-test/deep v1.0.3 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.3.0 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/gofrs/flock v0.12.1 // indirect
|
||||
|
@ -120,20 +115,12 @@ require (
|
|||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.14.2 // indirect
|
||||
github.com/gopherjs/gopherjs v1.17.2 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
||||
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 // indirect
|
||||
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
|
||||
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
|
||||
github.com/hashicorp/hcl v1.0.1-vault-7 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
|
@ -141,7 +128,6 @@ require (
|
|||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/ryanuber/go-glob v1.0.0 // indirect
|
||||
github.com/sergi/go-diff v1.2.0 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
|
|
43
go.sum
43
go.sum
|
@ -5,7 +5,6 @@ cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIi
|
|||
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
||||
cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU=
|
||||
cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo=
|
||||
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1 h1:Wc1ml6QlJs2BHQ/9Bqu1jiyggbsSjramq2oUmp5WeIo=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.1/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 h1:B+blDbyVIG3WaikNxPnhPiJ1MThR03b3vKGtER95TP4=
|
||||
|
@ -45,7 +44,6 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNg
|
|||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
|
||||
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.5 h1:0OF9RiEMEdDdZEMqF9MRjevyxAQcf6gY+E7vwBILFj0=
|
||||
github.com/aws/aws-sdk-go-v2 v1.36.5/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.29.17 h1:jSuiQ5jEe4SAMH6lLRMY9OVC+TqJLP5655pBGjmnjr0=
|
||||
|
@ -78,7 +76,6 @@ github.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw=
|
|||
github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
|
||||
github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0=
|
||||
github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6/go.mod h1:J29hk+f9lJrblVIfiJOtTFk+OblBawmib4uz/VdKzlg=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/billputer/go-namecheap v0.0.0-20210108011502-994a912fb7f9 h1:2vQTbEJvFsyd1VefzZ34GUkUD6TkJleYYJh9/25WBE4=
|
||||
github.com/billputer/go-namecheap v0.0.0-20210108011502-994a912fb7f9/go.mod h1:bqqNsI2akL+lLWyApkYY0cxquWPKwEBU0Wd3chi3TEg=
|
||||
github.com/bits-and-blooms/bitset v1.14.3 h1:Gd2c8lSNf9pKXom5JtD7AaKO8o7fGQ2LtFj1436qilA=
|
||||
|
@ -86,8 +83,6 @@ github.com/bits-and-blooms/bitset v1.14.3/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6
|
|||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
|
||||
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v4 v4.0.7 h1:Jk7uhY5q11fE5PlEupX2Lo12w82UhGC6bE1CI5jwFbc=
|
||||
github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v4 v4.0.7/go.mod h1:FnQtD0+Q/1NZxi0eEWN+3ZRyMsE9vzSB3YjyunkbKD0=
|
||||
|
@ -130,7 +125,6 @@ github.com/exoscale/egoscale v0.102.4 h1:GBKsZMIOzwBfSu+4ZmWka3Ejf2JLiaBDHp4CQUg
|
|||
github.com/exoscale/egoscale v0.102.4/go.mod h1:ROSmPtle0wvf91iLZb09++N/9BH2Jo9XxIpAEumvocA=
|
||||
github.com/failsafe-go/failsafe-go v0.6.9 h1:7HWEzOlFOjNerxgWd8onWA2j/aEuqyAtuX6uWya/364=
|
||||
github.com/failsafe-go/failsafe-go v0.6.9/go.mod h1:zb7xfp1/DJ7Mn4xJhVSZ9F2qmmMEGvYHxEOHYK5SIm0=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||
|
@ -143,13 +137,9 @@ github.com/getkin/kin-openapi v0.87.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSy
|
|||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
|
||||
github.com/go-acme/lego/v4 v4.24.0 h1:pe0q49JKxfSGEP3lkgkMVQrZM1KbD+e0dpJ2McYsiVw=
|
||||
github.com/go-acme/lego/v4 v4.24.0/go.mod h1:hkstZY6D0jylIrZbuNmEQrWQxTIfaJH7prwaWvKDOjw=
|
||||
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
|
||||
github.com/go-gandi/go-gandi v0.7.0 h1:gsP33dUspsN1M+ZW9HEgHchK9HiaSkYnltO73RHhSZA=
|
||||
github.com/go-gandi/go-gandi v0.7.0/go.mod h1:9NoYyfWCjFosClPiWjkbbRK5UViaZ4ctpT8/pKSSFlw=
|
||||
github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
|
||||
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
|
@ -166,8 +156,6 @@ github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn
|
|||
github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
|
||||
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||
github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk=
|
||||
github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/gobwas/glob v0.2.4-0.20181002190808-e7a84e9525fe h1:zn8tqiUbec4wR94o7Qj3LZCAT6uGobhEgnDRg6isG5U=
|
||||
|
@ -234,31 +222,12 @@ github.com/gopherjs/jquery v0.0.0-20191017083323-73f4c7416038/go.mod h1:xKR3tvLn
|
|||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
|
||||
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
|
||||
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 h1:om4Al8Oy7kCm/B86rLCLah4Dt5Aa0Fr5rYBG60OzwHQ=
|
||||
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8=
|
||||
github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U=
|
||||
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts=
|
||||
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4=
|
||||
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
|
||||
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
|
||||
github.com/hashicorp/hcl v1.0.1-vault-7 h1:ag5OxFVy3QYTFTJODRzTKVZ6xvdfLLCA1cy/Y6xGI0I=
|
||||
github.com/hashicorp/hcl v1.0.1-vault-7/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM=
|
||||
github.com/hashicorp/vault/api v1.20.0 h1:KQMHElgudOsr+IbJgmbjHnCTxEpKs9LnozA1D3nozU4=
|
||||
github.com/hashicorp/vault/api v1.20.0/go.mod h1:GZ4pcjfzoOWpkJ3ijHNpEoAxKEsBJnVljyTe3jM2Sms=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.158 h1:pRMfrWsWPE4belcRz5FtpGNyDxOCt32lDC6HpWojqGg=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.158/go.mod h1:Y/+YLCFCJtS29i2MbYPTUlNNfwXvkzEsZKR0imY/2aY=
|
||||
github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc=
|
||||
|
@ -303,11 +272,9 @@ github.com/luadns/luadns-go v0.3.0/go.mod h1:DmPXbrGMpynq1YNDpvgww3NP5Zf4wXM5raA
|
|||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
|
@ -317,13 +284,8 @@ github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04
|
|||
github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM=
|
||||
github.com/miekg/dns v1.1.67 h1:kg0EHj0G4bfT5/oOys6HhZw4vmMlnoZ+gDu8tJ/AlI0=
|
||||
github.com/miekg/dns v1.1.67/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mittwald/go-powerdns v0.6.7 h1:r638QOYLWyJ5Wy+qynlq5nTRlhmfQMJvM9BDsbhyiro=
|
||||
github.com/mittwald/go-powerdns v0.6.7/go.mod h1:zFe/i17IP6/NGFkWGGsPL0t7VrL6u14HU8Hr06X4Qmg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
|
@ -360,7 +322,6 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/pquerna/otp v1.5.0 h1:NMMR+WrmaqXU4EzdGJEE1aUUI0AMRzsp96fFFWNPwxs=
|
||||
github.com/pquerna/otp v1.5.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
|
@ -377,9 +338,6 @@ github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR
|
|||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
|
||||
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
||||
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
|
||||
|
@ -531,7 +489,6 @@ golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
|||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
327
pkg/acme/acme.go
327
pkg/acme/acme.go
|
@ -1,327 +0,0 @@
|
|||
// Package acme provides a means of performing Let's Encrypt DNS challenges via a DNSConfig
|
||||
package acme
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/nameservers"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/notifications"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/zonerecs"
|
||||
"github.com/go-acme/lego/v4/certcrypto"
|
||||
"github.com/go-acme/lego/v4/certificate"
|
||||
"github.com/go-acme/lego/v4/challenge"
|
||||
"github.com/go-acme/lego/v4/challenge/dns01"
|
||||
"github.com/go-acme/lego/v4/lego"
|
||||
acmelog "github.com/go-acme/lego/v4/log"
|
||||
)
|
||||
|
||||
// CertConfig describes a certificate's configuration.
|
||||
type CertConfig struct {
|
||||
CertName string `json:"cert_name"`
|
||||
Names []string `json:"names"`
|
||||
UseECC bool `json:"use_ecc"`
|
||||
MustStaple bool `json:"must_staple"`
|
||||
}
|
||||
|
||||
// Client is an interface for systems that issue or renew certs.
|
||||
type Client interface {
|
||||
IssueOrRenewCert(config *CertConfig, renewUnder int, verbose bool) (bool, error)
|
||||
}
|
||||
|
||||
type certManager struct {
|
||||
email string
|
||||
acmeDirectory string
|
||||
acmeHost string
|
||||
|
||||
storage Storage
|
||||
cfg *models.DNSConfig
|
||||
domains map[string]*models.DomainConfig
|
||||
originalDomains []*models.DomainConfig
|
||||
|
||||
notifier notifications.Notifier
|
||||
|
||||
account *Account
|
||||
waitedOnce bool
|
||||
}
|
||||
|
||||
const (
|
||||
// LetsEncryptLive is the endpoint for updates (production).
|
||||
LetsEncryptLive = "https://acme-v02.api.letsencrypt.org/directory"
|
||||
// LetsEncryptStage is the endpoint for the staging area.
|
||||
LetsEncryptStage = "https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||
)
|
||||
|
||||
// New is a factory for acme clients.
|
||||
func New(cfg *models.DNSConfig, directory string, email string, server string, notify notifications.Notifier) (Client, error) {
|
||||
return commonNew(cfg, directoryStorage(directory), email, server, notify)
|
||||
}
|
||||
|
||||
func commonNew(cfg *models.DNSConfig, storage Storage, email string, server string, notify notifications.Notifier) (Client, error) {
|
||||
u, err := url.Parse(server)
|
||||
if err != nil || u.Host == "" {
|
||||
return nil, fmt.Errorf("ACME directory '%s' is not a valid URL", server)
|
||||
}
|
||||
c := &certManager{
|
||||
storage: storage,
|
||||
email: email,
|
||||
acmeDirectory: server,
|
||||
acmeHost: u.Host,
|
||||
cfg: cfg,
|
||||
domains: map[string]*models.DomainConfig{},
|
||||
notifier: notify,
|
||||
}
|
||||
|
||||
acct, err := c.getOrCreateAccount()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.account = acct
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// NewVault is a factory for new vaunt clients.
|
||||
func NewVault(cfg *models.DNSConfig, vaultPath string, email string, server string, notify notifications.Notifier) (Client, error) {
|
||||
storage, err := makeVaultStorage(vaultPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return commonNew(cfg, storage, email, server, notify)
|
||||
}
|
||||
|
||||
// IssueOrRenewCert will obtain a certificate with the given name if it does not exist,
|
||||
// or renew it if it is close enough to the expiration date.
|
||||
// It will return true if it issued or updated the certificate.
|
||||
func (c *certManager) IssueOrRenewCert(cfg *CertConfig, renewUnder int, verbose bool) (bool, error) {
|
||||
if !verbose {
|
||||
acmelog.Logger = log.New(io.Discard, "", 0)
|
||||
}
|
||||
defer c.finalCleanUp() //nolint:errcheck
|
||||
|
||||
log.Printf("Checking certificate [%s]", cfg.CertName)
|
||||
existing, err := c.storage.GetCertificate(cfg.CertName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var client *lego.Client
|
||||
|
||||
action := func() (*certificate.Resource, error) {
|
||||
return client.Certificate.Obtain(certificate.ObtainRequest{
|
||||
Bundle: true,
|
||||
Domains: cfg.Names,
|
||||
MustStaple: cfg.MustStaple,
|
||||
})
|
||||
}
|
||||
|
||||
if existing == nil {
|
||||
log.Println("No existing cert found. Issuing new...")
|
||||
} else {
|
||||
names, daysLeft, err := getCertInfo(existing.Certificate)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
log.Printf("Found existing cert. %0.2f days remaining.", daysLeft)
|
||||
namesOK := dnsNamesEqual(cfg.Names, names)
|
||||
if daysLeft >= float64(renewUnder) && namesOK {
|
||||
log.Println("Nothing to do")
|
||||
// nothing to do
|
||||
return false, nil
|
||||
}
|
||||
if !namesOK {
|
||||
log.Println("DNS Names don't match expected set. Reissuing.")
|
||||
} else {
|
||||
log.Println("Renewing cert")
|
||||
action = func() (*certificate.Resource, error) {
|
||||
return client.Certificate.Renew(*existing, true, cfg.MustStaple, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kt := certcrypto.RSA2048
|
||||
if cfg.UseECC {
|
||||
kt = certcrypto.EC256
|
||||
}
|
||||
config := lego.NewConfig(c.account)
|
||||
config.CADirURL = c.acmeDirectory
|
||||
config.Certificate.KeyType = kt
|
||||
client, err = lego.NewClient(config)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
client.Challenge.Remove(challenge.HTTP01)
|
||||
client.Challenge.Remove(challenge.TLSALPN01)
|
||||
client.Challenge.SetDNS01Provider(c, dns01.WrapPreCheck(c.preCheckDNS)) //nolint:errcheck
|
||||
|
||||
certResource, err := action()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
fmt.Printf("Obtained certificate for %s\n", cfg.CertName)
|
||||
if err = c.storage.StoreCertificate(cfg.CertName, certResource); err != nil {
|
||||
return true, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func getCertInfo(pemBytes []byte) (names []string, remaining float64, err error) {
|
||||
block, _ := pem.Decode(pemBytes)
|
||||
if block == nil {
|
||||
return nil, 0, errors.New("invalid certificate PEM data")
|
||||
}
|
||||
cert, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
daysLeft := float64(time.Until(cert.NotAfter)) / float64(time.Hour*24)
|
||||
return cert.DNSNames, daysLeft, nil
|
||||
}
|
||||
|
||||
// checks two lists of sans to make sure they have all the same names in them.
|
||||
func dnsNamesEqual(a []string, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
sort.Strings(a)
|
||||
sort.Strings(b)
|
||||
for i, s := range a {
|
||||
if b[i] != s {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *certManager) Present(domain, token, keyAuth string) (e error) {
|
||||
d := c.cfg.DomainContainingFQDN(domain)
|
||||
name := d.Name
|
||||
if seen := c.domains[name]; seen != nil {
|
||||
// we've already pre-processed this domain, just need to add to it.
|
||||
d = seen
|
||||
} else {
|
||||
// one-time tasks to get this domain ready.
|
||||
// if multiple validations on a single domain, we don't need to rebuild all this.
|
||||
|
||||
// fix NS records for this domain's DNS providers
|
||||
nsList, err := nameservers.DetermineNameservers(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Nameservers = nsList
|
||||
nameservers.AddNSRecords(d)
|
||||
|
||||
// make sure we have the latest config before we change anything.
|
||||
// alternately, we could avoid a lot of this trouble if we really trusted no-purge in all cases
|
||||
if err := c.ensureNoPendingCorrections(d); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Copy domain and work from cpy from now on. That way original config can be used to "restore" when we are all done.
|
||||
cpy, err := d.Copy()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.originalDomains = append(c.originalDomains, d)
|
||||
c.domains[name] = cpy
|
||||
d = cpy
|
||||
}
|
||||
|
||||
fqdn, val := dns01.GetRecord(domain, keyAuth)
|
||||
txt := &models.RecordConfig{Type: "TXT"}
|
||||
if err := txt.SetTargetTXT(val); err != nil {
|
||||
return err
|
||||
}
|
||||
txt.SetLabelFromFQDN(fqdn, d.Name)
|
||||
d.Records = append(d.Records, txt)
|
||||
return c.getAndRunCorrections(d)
|
||||
}
|
||||
|
||||
func (c *certManager) ensureNoPendingCorrections(d *models.DomainConfig) error {
|
||||
corrections, err := c.getCorrections(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(corrections) != 0 {
|
||||
// TODO: maybe allow forcing through this check.
|
||||
for _, c := range corrections {
|
||||
fmt.Println(c.Msg)
|
||||
}
|
||||
return fmt.Errorf("found %d pending corrections for %s. Not going to proceed issuing certificates", len(corrections), d.Name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IgnoredProviders is a list of provider names that should not be used to fill challenges.
|
||||
var IgnoredProviders = map[string]bool{}
|
||||
|
||||
func (c *certManager) getCorrections(d *models.DomainConfig) ([]*models.Correction, error) {
|
||||
cs := []*models.Correction{}
|
||||
for _, p := range d.DNSProviderInstances {
|
||||
if IgnoredProviders[p.Name] {
|
||||
continue
|
||||
}
|
||||
dc, err := d.Copy()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reports, corrections, _, err := zonerecs.CorrectZoneRecords(p.Driver, dc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, c := range reports {
|
||||
c.Msg = fmt.Sprintf("INFO[%s] %s", p.Name, strings.TrimSpace(c.Msg))
|
||||
}
|
||||
for _, c := range corrections {
|
||||
c.Msg = fmt.Sprintf("[%s] %s", p.Name, strings.TrimSpace(c.Msg))
|
||||
}
|
||||
cs = append(cs, corrections...)
|
||||
}
|
||||
return cs, nil
|
||||
}
|
||||
|
||||
func (c *certManager) getAndRunCorrections(d *models.DomainConfig) error {
|
||||
cs, err := c.getCorrections(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("%d corrections\n", len(cs))
|
||||
for _, corr := range cs {
|
||||
fmt.Printf("Running [%s]\n", corr.Msg)
|
||||
err = corr.F()
|
||||
err2 := c.notifier.Notify(d.Name, "certs", corr.Msg, err, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *certManager) CleanUp(domain, token, keyAuth string) error {
|
||||
// do nothing for now. We will do a final clean up step at the very end.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *certManager) finalCleanUp() error {
|
||||
log.Println("Cleaning up all records we made")
|
||||
var lastError error
|
||||
for _, d := range c.originalDomains {
|
||||
if err := c.getAndRunCorrections(d); err != nil {
|
||||
log.Printf("ERROR cleaning up: %s", err)
|
||||
lastError = err
|
||||
}
|
||||
}
|
||||
return lastError
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
package acme
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/challenge/dns01"
|
||||
)
|
||||
|
||||
func (c *certManager) preCheckDNS(domain, fqdn, value string, native dns01.PreCheckFunc) (bool, error) {
|
||||
// default record verification in the client library makes sure the authoritative nameservers
|
||||
// have the expected records.
|
||||
// Sometimes the Let's Encrypt verification fails anyway because records have not propagated the provider's network fully.
|
||||
// So we add an additional 60 second sleep just for safety.
|
||||
v, err := native(fqdn, value)
|
||||
if err != nil {
|
||||
return v, err
|
||||
}
|
||||
if !c.waitedOnce {
|
||||
log.Printf("DNS ok. Waiting another 60s to ensure stability.")
|
||||
time.Sleep(60 * time.Second)
|
||||
c.waitedOnce = true
|
||||
}
|
||||
log.Printf("DNS records seem to exist. Proceeding to request validation")
|
||||
return v, err
|
||||
}
|
||||
|
||||
// Timeout increases the client-side polling check time to five minutes with one second waits in-between.
|
||||
func (c *certManager) Timeout() (timeout, interval time.Duration) {
|
||||
return 5 * time.Minute, time.Second
|
||||
}
|
|
@ -1,140 +0,0 @@
|
|||
package acme
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/go-acme/lego/v4/certificate"
|
||||
)
|
||||
|
||||
// directoryStorage implements storage in a local file directory
|
||||
type directoryStorage string
|
||||
|
||||
// filename for certificate / key / json file
|
||||
func (d directoryStorage) certFile(name, ext string) string {
|
||||
return filepath.Join(d.certDir(name), name+"."+ext)
|
||||
}
|
||||
|
||||
func (d directoryStorage) certDir(name string) string {
|
||||
return filepath.Join(string(d), "certificates", name)
|
||||
}
|
||||
|
||||
func (d directoryStorage) accountDirectory(acmeHost string) string {
|
||||
return filepath.Join(string(d), ".letsencrypt", acmeHost)
|
||||
}
|
||||
|
||||
func (d directoryStorage) accountFile(acmeHost string) string {
|
||||
return filepath.Join(d.accountDirectory(acmeHost), "account.json")
|
||||
}
|
||||
|
||||
func (d directoryStorage) accountKeyFile(acmeHost string) string {
|
||||
return filepath.Join(d.accountDirectory(acmeHost), "account.key")
|
||||
}
|
||||
|
||||
const (
|
||||
perms os.FileMode = 0o600
|
||||
dirPerms os.FileMode = 0o700
|
||||
)
|
||||
|
||||
func (d directoryStorage) GetCertificate(name string) (*certificate.Resource, error) {
|
||||
f, err := os.Open(d.certFile(name, "json"))
|
||||
if err != nil && os.IsNotExist(err) {
|
||||
// if json does not exist, nothing does
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
dec := json.NewDecoder(f)
|
||||
cr := &certificate.Resource{}
|
||||
if err = dec.Decode(cr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// load cert
|
||||
crtBytes, err := os.ReadFile(d.certFile(name, "crt"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cr.Certificate = crtBytes
|
||||
return cr, nil
|
||||
}
|
||||
|
||||
func (d directoryStorage) StoreCertificate(name string, cert *certificate.Resource) error {
|
||||
// make sure actual cert data never gets into metadata json
|
||||
if err := os.MkdirAll(d.certDir(name), dirPerms); err != nil {
|
||||
return err
|
||||
}
|
||||
pub := cert.Certificate
|
||||
cert.Certificate = nil
|
||||
priv := cert.PrivateKey
|
||||
cert.PrivateKey = nil
|
||||
combined := []byte(string(pub) + "\n" + string(priv))
|
||||
jDAt, err := json.MarshalIndent(cert, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = os.WriteFile(d.certFile(name, "json"), jDAt, perms); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = os.WriteFile(d.certFile(name, "crt"), pub, perms); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = os.WriteFile(d.certFile(name, "pem"), combined, perms); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(d.certFile(name, "key"), priv, perms)
|
||||
}
|
||||
|
||||
func (d directoryStorage) GetAccount(acmeHost string) (*Account, error) {
|
||||
f, err := os.Open(d.accountFile(acmeHost))
|
||||
if err != nil && os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
dec := json.NewDecoder(f)
|
||||
acct := &Account{}
|
||||
if err = dec.Decode(acct); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keyBytes, err := os.ReadFile(d.accountKeyFile(acmeHost))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keyBlock, _ := pem.Decode(keyBytes)
|
||||
if keyBlock == nil {
|
||||
return nil, errors.New("error decoding account private key")
|
||||
}
|
||||
acct.key, err = x509.ParseECPrivateKey(keyBlock.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return acct, nil
|
||||
}
|
||||
|
||||
func (d directoryStorage) StoreAccount(acmeHost string, account *Account) error {
|
||||
if err := os.MkdirAll(d.accountDirectory(acmeHost), dirPerms); err != nil {
|
||||
return err
|
||||
}
|
||||
acctBytes, err := json.MarshalIndent(account, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = os.WriteFile(d.accountFile(acmeHost), acctBytes, perms); err != nil {
|
||||
return err
|
||||
}
|
||||
keyBytes, err := x509.MarshalECPrivateKey(account.key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pemKey := &pem.Block{Type: "EC PRIVATE KEY", Bytes: keyBytes}
|
||||
pemBytes := pem.EncodeToMemory(pemKey)
|
||||
return os.WriteFile(d.accountKeyFile(acmeHost), pemBytes, perms)
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
package acme
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
|
||||
"github.com/go-acme/lego/v4/certcrypto"
|
||||
"github.com/go-acme/lego/v4/lego"
|
||||
"github.com/go-acme/lego/v4/registration"
|
||||
)
|
||||
|
||||
func (c *certManager) getOrCreateAccount() (*Account, error) {
|
||||
account, err := c.storage.GetAccount(c.acmeHost)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if account != nil {
|
||||
return account, nil
|
||||
}
|
||||
// register new
|
||||
account, err = c.createAccount(c.email)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = c.storage.StoreAccount(c.acmeHost, account)
|
||||
return account, err
|
||||
}
|
||||
|
||||
// func (c *certManager) createAccount(email string) (*Account, error) {
|
||||
func (c *certManager) createAccount(_ string) (*Account, error) {
|
||||
privateKey, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
acct := &Account{
|
||||
key: privateKey,
|
||||
Email: c.email,
|
||||
}
|
||||
config := lego.NewConfig(acct)
|
||||
config.CADirURL = c.acmeDirectory
|
||||
config.Certificate.KeyType = certcrypto.EC384
|
||||
client, err := lego.NewClient(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reg, err := client.Registration.Register(registration.RegisterOptions{TermsOfServiceAgreed: true})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
acct.Registration = reg
|
||||
return acct, nil
|
||||
}
|
||||
|
||||
// Account stores the data related to an ACME account.
|
||||
type Account struct {
|
||||
Email string `json:"email"`
|
||||
Registration *registration.Resource `json:"registration"`
|
||||
key *ecdsa.PrivateKey
|
||||
}
|
||||
|
||||
// GetEmail is a getter for the Email field.
|
||||
func (a *Account) GetEmail() string {
|
||||
return a.Email
|
||||
}
|
||||
|
||||
// GetPrivateKey is a getter for the PrivateKey field.
|
||||
func (a *Account) GetPrivateKey() crypto.PrivateKey {
|
||||
return a.key
|
||||
}
|
||||
|
||||
// GetRegistration is a getter for the registration field.
|
||||
func (a *Account) GetRegistration() *registration.Resource {
|
||||
return a.Registration
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package acme
|
||||
|
||||
import "github.com/go-acme/lego/v4/certificate"
|
||||
|
||||
// Storage is an abstracrion around how certificates, keys, and account info are stored on disk or elsewhere.
|
||||
type Storage interface {
|
||||
// Get Existing certificate, or return nil if it does not exist
|
||||
GetCertificate(name string) (*certificate.Resource, error)
|
||||
StoreCertificate(name string, cert *certificate.Resource) error
|
||||
|
||||
GetAccount(acmeHost string) (*Account, error)
|
||||
StoreAccount(acmeHost string, account *Account) error
|
||||
}
|
|
@ -1,152 +0,0 @@
|
|||
package acme
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/go-acme/lego/v4/certificate"
|
||||
"github.com/hashicorp/vault/api"
|
||||
)
|
||||
|
||||
type vaultStorage struct {
|
||||
path string
|
||||
client *api.Logical
|
||||
}
|
||||
|
||||
func makeVaultStorage(vaultPath string) (Storage, error) {
|
||||
if !strings.HasSuffix(vaultPath, "/") {
|
||||
vaultPath += "/"
|
||||
}
|
||||
client, err := api.NewClient(api.DefaultConfig())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
storage := &vaultStorage{
|
||||
path: vaultPath,
|
||||
client: client.Logical(),
|
||||
}
|
||||
return storage, nil
|
||||
}
|
||||
|
||||
func (v *vaultStorage) GetCertificate(name string) (*certificate.Resource, error) {
|
||||
var err error
|
||||
|
||||
path := v.certPath(name)
|
||||
secret, err := v.client.Read(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if secret == nil {
|
||||
return nil, nil
|
||||
}
|
||||
cert := &certificate.Resource{}
|
||||
if dat, err := v.getString("meta", secret.Data, path); err != nil {
|
||||
return nil, err
|
||||
} else if err = json.Unmarshal(dat, cert); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var dat []byte
|
||||
if dat, err = v.getString("tls.cert", secret.Data, path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cert.Certificate = dat
|
||||
|
||||
if dat, err = v.getString("tls.key", secret.Data, path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cert.PrivateKey = dat
|
||||
|
||||
return cert, nil
|
||||
}
|
||||
|
||||
func (v *vaultStorage) getString(key string, data map[string]interface{}, path string) ([]byte, error) {
|
||||
dat, ok := data[key]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("secret at %s does not have key %s", path, key)
|
||||
}
|
||||
str, ok := dat.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("secret at %s is not string", path)
|
||||
}
|
||||
return []byte(str), nil
|
||||
}
|
||||
|
||||
func (v *vaultStorage) StoreCertificate(name string, cert *certificate.Resource) error {
|
||||
jDat, err := json.MarshalIndent(cert, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pub := string(cert.Certificate)
|
||||
key := string(cert.PrivateKey)
|
||||
data := map[string]interface{}{
|
||||
"tls.cert": pub,
|
||||
"tls.key": key,
|
||||
"tls.combined": pub + "\n" + key,
|
||||
"meta": string(jDat),
|
||||
}
|
||||
_, err = v.client.Write(v.certPath(name), data)
|
||||
return err
|
||||
}
|
||||
|
||||
func (v *vaultStorage) registrationPath(acmeHost string) string {
|
||||
return v.path + ".letsencrypt/" + acmeHost
|
||||
}
|
||||
|
||||
func (v *vaultStorage) certPath(name string) string {
|
||||
return v.path + name
|
||||
}
|
||||
|
||||
func (v *vaultStorage) GetAccount(acmeHost string) (*Account, error) {
|
||||
path := v.registrationPath(acmeHost)
|
||||
secret, err := v.client.Read(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if secret == nil {
|
||||
return nil, nil
|
||||
}
|
||||
acct := &Account{}
|
||||
if dat, err := v.getString("registration", secret.Data, path); err != nil {
|
||||
return nil, err
|
||||
} else if err = json.Unmarshal(dat, acct); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var key *ecdsa.PrivateKey
|
||||
var dat []byte
|
||||
var block *pem.Block
|
||||
if dat, err = v.getString("tls.key", secret.Data, path); err != nil {
|
||||
return nil, err
|
||||
} else if block, _ = pem.Decode(dat); block == nil {
|
||||
return nil, errors.New("error decoding account private key")
|
||||
} else if key, err = x509.ParseECPrivateKey(block.Bytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
acct.key = key
|
||||
return acct, nil
|
||||
}
|
||||
|
||||
func (v *vaultStorage) StoreAccount(acmeHost string, account *Account) error {
|
||||
acctBytes, err := json.MarshalIndent(account, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
keyBytes, err := x509.MarshalECPrivateKey(account.key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pemKey := &pem.Block{Type: "EC PRIVATE KEY", Bytes: keyBytes}
|
||||
pemBytes := pem.EncodeToMemory(pemKey)
|
||||
|
||||
_, err = v.client.Write(v.registrationPath(acmeHost), map[string]interface{}{
|
||||
"registration": string(acctBytes),
|
||||
"tls.key": string(pemBytes),
|
||||
})
|
||||
return err
|
||||
}
|
Loading…
Add table
Reference in a new issue