github.com/hexonet/dnscontrol@v0.2.8/pkg/acme/vaultStorage.go (about) 1 package acme 2 3 import ( 4 "crypto/x509" 5 "encoding/json" 6 "encoding/pem" 7 "fmt" 8 "strings" 9 10 "github.com/xenolf/lego/acme" 11 12 "github.com/hashicorp/vault/api" 13 ) 14 15 type vaultStorage struct { 16 path string 17 client *api.Logical 18 } 19 20 func makeVaultStorage(vaultPath string) (Storage, error) { 21 if !strings.HasSuffix(vaultPath, "/") { 22 vaultPath += "/" 23 } 24 client, err := api.NewClient(api.DefaultConfig()) 25 if err != nil { 26 return nil, err 27 } 28 storage := &vaultStorage{ 29 path: vaultPath, 30 client: client.Logical(), 31 } 32 return storage, nil 33 } 34 35 func (v *vaultStorage) GetCertificate(name string) (*acme.CertificateResource, error) { 36 path := v.certPath(name) 37 secret, err := v.client.Read(path) 38 if err != nil { 39 return nil, err 40 } 41 if secret == nil { 42 return nil, nil 43 } 44 cert := &acme.CertificateResource{} 45 if dat, err := v.getString("meta", secret.Data, path); err != nil { 46 return nil, err 47 } else if err = json.Unmarshal(dat, cert); err != nil { 48 return nil, err 49 } 50 51 if dat, err := v.getString("tls.cert", secret.Data, path); err != nil { 52 return nil, err 53 } else { 54 cert.Certificate = dat 55 } 56 57 if dat, err := v.getString("tls.key", secret.Data, path); err != nil { 58 return nil, err 59 } else { 60 cert.PrivateKey = dat 61 } 62 63 return cert, nil 64 } 65 66 func (v *vaultStorage) getString(key string, data map[string]interface{}, path string) ([]byte, error) { 67 dat, ok := data[key] 68 if !ok { 69 return nil, fmt.Errorf("Secret at %s does not have key %s", path, key) 70 } 71 str, ok := dat.(string) 72 if !ok { 73 return nil, fmt.Errorf("Secret at %s is not string", path) 74 } 75 return []byte(str), nil 76 } 77 78 func (v *vaultStorage) StoreCertificate(name string, cert *acme.CertificateResource) error { 79 jDat, err := json.MarshalIndent(cert, "", " ") 80 if err != nil { 81 return err 82 } 83 data := map[string]interface{}{ 84 "tls.cert": string(cert.Certificate), 85 "tls.key": string(cert.PrivateKey), 86 "meta": string(jDat), 87 } 88 _, err = v.client.Write(v.certPath(name), data) 89 return err 90 } 91 92 func (v *vaultStorage) registrationPath(acmeHost string) string { 93 return v.path + ".letsencrypt/" + acmeHost 94 } 95 96 func (v *vaultStorage) certPath(name string) string { 97 return v.path + name 98 } 99 100 func (v *vaultStorage) GetAccount(acmeHost string) (*Account, error) { 101 path := v.registrationPath(acmeHost) 102 secret, err := v.client.Read(path) 103 if err != nil { 104 return nil, err 105 } 106 if secret == nil { 107 return nil, nil 108 } 109 acct := &Account{} 110 if dat, err := v.getString("registration", secret.Data, path); err != nil { 111 return nil, err 112 } else if err = json.Unmarshal(dat, acct); err != nil { 113 return nil, err 114 } 115 116 if dat, err := v.getString("tls.key", secret.Data, path); err != nil { 117 return nil, err 118 } else if block, _ := pem.Decode(dat); block == nil { 119 return nil, fmt.Errorf("Error decoding account private key") 120 } else if key, err := x509.ParseECPrivateKey(block.Bytes); err != nil { 121 return nil, err 122 } else { 123 acct.key = key 124 } 125 126 return acct, nil 127 } 128 129 func (v *vaultStorage) StoreAccount(acmeHost string, account *Account) error { 130 acctBytes, err := json.MarshalIndent(account, "", " ") 131 if err != nil { 132 return err 133 } 134 keyBytes, err := x509.MarshalECPrivateKey(account.key) 135 if err != nil { 136 return err 137 } 138 pemKey := &pem.Block{Type: "EC PRIVATE KEY", Bytes: keyBytes} 139 pemBytes := pem.EncodeToMemory(pemKey) 140 141 _, err = v.client.Write(v.registrationPath(acmeHost), map[string]interface{}{ 142 "registration": string(acctBytes), 143 "tls.key": string(pemBytes), 144 }) 145 return err 146 }