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