1*e7b1675dSTing-Kang Chang// Copyright 2019 Google Inc. 2*e7b1675dSTing-Kang Chang// 3*e7b1675dSTing-Kang Chang// Licensed under the Apache License, Version 2.0 (the "License"); 4*e7b1675dSTing-Kang Chang// you may not use this file except in compliance with the License. 5*e7b1675dSTing-Kang Chang// You may obtain a copy of the License at 6*e7b1675dSTing-Kang Chang// 7*e7b1675dSTing-Kang Chang// http://www.apache.org/licenses/LICENSE-2.0 8*e7b1675dSTing-Kang Chang// 9*e7b1675dSTing-Kang Chang// Unless required by applicable law or agreed to in writing, software 10*e7b1675dSTing-Kang Chang// distributed under the License is distributed on an "AS IS" BASIS, 11*e7b1675dSTing-Kang Chang// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*e7b1675dSTing-Kang Chang// See the License for the specific language governing permissions and 13*e7b1675dSTing-Kang Chang// limitations under the License. 14*e7b1675dSTing-Kang Chang// 15*e7b1675dSTing-Kang Chang//////////////////////////////////////////////////////////////////////////////// 16*e7b1675dSTing-Kang Chang 17*e7b1675dSTing-Kang Chang// Package hcvault provides integration with the [HashiCorp Vault]. 18*e7b1675dSTing-Kang Chang// 19*e7b1675dSTing-Kang Chang// [HashiCorp Vault]: https://www.vaultproject.io/. 20*e7b1675dSTing-Kang Changpackage hcvault 21*e7b1675dSTing-Kang Chang 22*e7b1675dSTing-Kang Changimport ( 23*e7b1675dSTing-Kang Chang "crypto/tls" 24*e7b1675dSTing-Kang Chang "errors" 25*e7b1675dSTing-Kang Chang "fmt" 26*e7b1675dSTing-Kang Chang "net/http" 27*e7b1675dSTing-Kang Chang "net/url" 28*e7b1675dSTing-Kang Chang "strings" 29*e7b1675dSTing-Kang Chang 30*e7b1675dSTing-Kang Chang "github.com/google/tink/go/core/registry" 31*e7b1675dSTing-Kang Chang "github.com/google/tink/go/tink" 32*e7b1675dSTing-Kang Chang "github.com/hashicorp/vault/api" 33*e7b1675dSTing-Kang Chang) 34*e7b1675dSTing-Kang Chang 35*e7b1675dSTing-Kang Changconst ( 36*e7b1675dSTing-Kang Chang vaultPrefix = "hcvault://" 37*e7b1675dSTing-Kang Chang) 38*e7b1675dSTing-Kang Chang 39*e7b1675dSTing-Kang Chang// vaultClient represents a client that connects to the HashiCorp Vault backend. 40*e7b1675dSTing-Kang Changtype vaultClient struct { 41*e7b1675dSTing-Kang Chang keyURIPrefix string 42*e7b1675dSTing-Kang Chang client *api.Logical 43*e7b1675dSTing-Kang Chang} 44*e7b1675dSTing-Kang Chang 45*e7b1675dSTing-Kang Changvar _ registry.KMSClient = (*vaultClient)(nil) 46*e7b1675dSTing-Kang Chang 47*e7b1675dSTing-Kang Chang// NewClient returns a new client to HashiCorp Vault. 48*e7b1675dSTing-Kang Chang// uriPrefix parameter is a valid URI which must have "hcvault" scheme and 49*e7b1675dSTing-Kang Chang// vault server address and port. Specific key URIs will be matched against this 50*e7b1675dSTing-Kang Chang// prefix to determine if the client supports the key or not. 51*e7b1675dSTing-Kang Chang// tlsCfg represents tls.Config which will be used to communicate with Vault 52*e7b1675dSTing-Kang Chang// server via HTTPS protocol. If not specified a default tls.Config{} will be 53*e7b1675dSTing-Kang Chang// used. 54*e7b1675dSTing-Kang Changfunc NewClient(uriPrefix string, tlsCfg *tls.Config, token string) (registry.KMSClient, error) { 55*e7b1675dSTing-Kang Chang if !strings.HasPrefix(strings.ToLower(uriPrefix), vaultPrefix) { 56*e7b1675dSTing-Kang Chang return nil, fmt.Errorf("key URI must start with %s", vaultPrefix) 57*e7b1675dSTing-Kang Chang } 58*e7b1675dSTing-Kang Chang 59*e7b1675dSTing-Kang Chang httpClient := api.DefaultConfig().HttpClient 60*e7b1675dSTing-Kang Chang transport := httpClient.Transport.(*http.Transport) 61*e7b1675dSTing-Kang Chang if tlsCfg == nil { 62*e7b1675dSTing-Kang Chang tlsCfg = &tls.Config{} 63*e7b1675dSTing-Kang Chang } else { 64*e7b1675dSTing-Kang Chang tlsCfg = tlsCfg.Clone() 65*e7b1675dSTing-Kang Chang } 66*e7b1675dSTing-Kang Chang transport.TLSClientConfig = tlsCfg 67*e7b1675dSTing-Kang Chang 68*e7b1675dSTing-Kang Chang vurl, err := url.Parse(uriPrefix) 69*e7b1675dSTing-Kang Chang if err != nil { 70*e7b1675dSTing-Kang Chang return nil, err 71*e7b1675dSTing-Kang Chang } 72*e7b1675dSTing-Kang Chang 73*e7b1675dSTing-Kang Chang cfg := &api.Config{ 74*e7b1675dSTing-Kang Chang Address: "https://" + vurl.Host, 75*e7b1675dSTing-Kang Chang HttpClient: httpClient, 76*e7b1675dSTing-Kang Chang } 77*e7b1675dSTing-Kang Chang 78*e7b1675dSTing-Kang Chang client, err := api.NewClient(cfg) 79*e7b1675dSTing-Kang Chang if err != nil { 80*e7b1675dSTing-Kang Chang return nil, err 81*e7b1675dSTing-Kang Chang } 82*e7b1675dSTing-Kang Chang 83*e7b1675dSTing-Kang Chang client.SetToken(token) 84*e7b1675dSTing-Kang Chang return &vaultClient{ 85*e7b1675dSTing-Kang Chang keyURIPrefix: uriPrefix, 86*e7b1675dSTing-Kang Chang client: client.Logical(), 87*e7b1675dSTing-Kang Chang }, nil 88*e7b1675dSTing-Kang Chang 89*e7b1675dSTing-Kang Chang} 90*e7b1675dSTing-Kang Chang 91*e7b1675dSTing-Kang Chang// Supported returns true if this client does support keyURI. 92*e7b1675dSTing-Kang Changfunc (c *vaultClient) Supported(keyURI string) bool { 93*e7b1675dSTing-Kang Chang return strings.HasPrefix(keyURI, c.keyURIPrefix) 94*e7b1675dSTing-Kang Chang} 95*e7b1675dSTing-Kang Chang 96*e7b1675dSTing-Kang Chang// GetAEAD gets an AEAD backend by keyURI. 97*e7b1675dSTing-Kang Changfunc (c *vaultClient) GetAEAD(keyURI string) (tink.AEAD, error) { 98*e7b1675dSTing-Kang Chang if !c.Supported(keyURI) { 99*e7b1675dSTing-Kang Chang return nil, errors.New("unsupported keyURI") 100*e7b1675dSTing-Kang Chang } 101*e7b1675dSTing-Kang Chang 102*e7b1675dSTing-Kang Chang return newHCVaultAEAD(keyURI, c.client) 103*e7b1675dSTing-Kang Chang} 104