From a8a3ea73bae3f59cfce7fb8159c51f6772c0f42e Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Mon, 14 Jul 2025 15:40:31 -0400 Subject: [PATCH] CHORE: remove unused module pkg/acme (get-certs) (#3667) --- go.mod | 14 -- go.sum | 43 ----- pkg/acme/acme.go | 327 ----------------------------------- pkg/acme/checkDns.go | 31 ---- pkg/acme/directoryStorage.go | 140 --------------- pkg/acme/registration.go | 76 -------- pkg/acme/storage.go | 13 -- pkg/acme/vaultStorage.go | 152 ---------------- 8 files changed, 796 deletions(-) delete mode 100644 pkg/acme/acme.go delete mode 100644 pkg/acme/checkDns.go delete mode 100644 pkg/acme/directoryStorage.go delete mode 100644 pkg/acme/registration.go delete mode 100644 pkg/acme/storage.go delete mode 100644 pkg/acme/vaultStorage.go diff --git a/go.mod b/go.mod index 19a3252ed..f3fa32165 100644 --- a/go.mod +++ b/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 diff --git a/go.sum b/go.sum index 96e77ec13..6fd02ddae 100644 --- a/go.sum +++ b/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= diff --git a/pkg/acme/acme.go b/pkg/acme/acme.go deleted file mode 100644 index 14d7b7655..000000000 --- a/pkg/acme/acme.go +++ /dev/null @@ -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 -} diff --git a/pkg/acme/checkDns.go b/pkg/acme/checkDns.go deleted file mode 100644 index b853271e3..000000000 --- a/pkg/acme/checkDns.go +++ /dev/null @@ -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 -} diff --git a/pkg/acme/directoryStorage.go b/pkg/acme/directoryStorage.go deleted file mode 100644 index cddfed974..000000000 --- a/pkg/acme/directoryStorage.go +++ /dev/null @@ -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) -} diff --git a/pkg/acme/registration.go b/pkg/acme/registration.go deleted file mode 100644 index 5e7214339..000000000 --- a/pkg/acme/registration.go +++ /dev/null @@ -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 -} diff --git a/pkg/acme/storage.go b/pkg/acme/storage.go deleted file mode 100644 index 29e751bce..000000000 --- a/pkg/acme/storage.go +++ /dev/null @@ -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 -} diff --git a/pkg/acme/vaultStorage.go b/pkg/acme/vaultStorage.go deleted file mode 100644 index 7efca7810..000000000 --- a/pkg/acme/vaultStorage.go +++ /dev/null @@ -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 -}