github.com/teknogeek/dnscontrol/v2@v2.10.1-0.20200227202244-ae299b55ba42/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/go-acme/lego/certificate" 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) (*certificate.Resource, 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 := &certificate.Resource{} 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 *certificate.Resource) error { 79 jDat, err := json.MarshalIndent(cert, "", " ") 80 if err != nil { 81 return err 82 } 83 pub := string(cert.Certificate) 84 key := string(cert.PrivateKey) 85 data := map[string]interface{}{ 86 "tls.cert": pub, 87 "tls.key": key, 88 "tls.combined": pub + "\n" + key, 89 "meta": string(jDat), 90 } 91 _, err = v.client.Write(v.certPath(name), data) 92 return err 93 } 94 95 func (v *vaultStorage) registrationPath(acmeHost string) string { 96 return v.path + ".letsencrypt/" + acmeHost 97 } 98 99 func (v *vaultStorage) certPath(name string) string { 100 return v.path + name 101 } 102 103 func (v *vaultStorage) GetAccount(acmeHost string) (*Account, error) { 104 path := v.registrationPath(acmeHost) 105 secret, err := v.client.Read(path) 106 if err != nil { 107 return nil, err 108 } 109 if secret == nil { 110 return nil, nil 111 } 112 acct := &Account{} 113 if dat, err := v.getString("registration", secret.Data, path); err != nil { 114 return nil, err 115 } else if err = json.Unmarshal(dat, acct); err != nil { 116 return nil, err 117 } 118 119 if dat, err := v.getString("tls.key", secret.Data, path); err != nil { 120 return nil, err 121 } else if block, _ := pem.Decode(dat); block == nil { 122 return nil, fmt.Errorf("Error decoding account private key") 123 } else if key, err := x509.ParseECPrivateKey(block.Bytes); err != nil { 124 return nil, err 125 } else { 126 acct.key = key 127 } 128 129 return acct, nil 130 } 131 132 func (v *vaultStorage) StoreAccount(acmeHost string, account *Account) error { 133 acctBytes, err := json.MarshalIndent(account, "", " ") 134 if err != nil { 135 return err 136 } 137 keyBytes, err := x509.MarshalECPrivateKey(account.key) 138 if err != nil { 139 return err 140 } 141 pemKey := &pem.Block{Type: "EC PRIVATE KEY", Bytes: keyBytes} 142 pemBytes := pem.EncodeToMemory(pemKey) 143 144 _, err = v.client.Write(v.registrationPath(acmeHost), map[string]interface{}{ 145 "registration": string(acctBytes), 146 "tls.key": string(pemBytes), 147 }) 148 return err 149 }