Skip to content

Commit a29d79b

Browse files
authored
Update HTTP transport wrapper to support TLSConfig cloning (hashicorp#1926)
* Extend auth_login_cert tests * Adapt tests to work with upstream vault/api changes
1 parent b874baa commit a29d79b

14 files changed

+571
-74
lines changed

go.mod

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ require (
3737
github.com/hashicorp/vault-plugin-auth-jwt v0.13.2-0.20221012184020-28cc68ee722b
3838
github.com/hashicorp/vault-plugin-auth-kerberos v0.8.0
3939
github.com/hashicorp/vault-plugin-auth-oci v0.13.0-pre
40-
github.com/hashicorp/vault/api v1.8.1
40+
github.com/hashicorp/vault/api v1.9.3-0.20230628215639-3ca33976762c
4141
github.com/hashicorp/vault/sdk v0.6.0
4242
github.com/hashicorp/yamux v0.1.1 // indirect
4343
github.com/jcmturner/gokrb5/v8 v8.4.2
@@ -46,7 +46,7 @@ require (
4646
github.com/mitchellh/mapstructure v1.5.0
4747
github.com/mitchellh/pointerstructure v1.2.1 // indirect
4848
go.uber.org/atomic v1.10.0 // indirect
49-
golang.org/x/crypto v0.0.0-20221012134737-56aed061732a
49+
golang.org/x/crypto v0.6.0
5050
golang.org/x/net v0.7.0
5151
golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1
5252
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect

go.sum

+8-4
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,8 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9
762762
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
763763
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
764764
github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
765+
github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo=
766+
github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
765767
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
766768
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
767769
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
@@ -1238,8 +1240,8 @@ github.com/hashicorp/vault/api v1.3.1/go.mod h1:QeJoWxMFt+MsuWcYhmwRLwKEXrjwAFFy
12381240
github.com/hashicorp/vault/api v1.5.0/go.mod h1:LkMdrZnWNrFaQyYYazWVn7KshilfDidgVBq6YiTq/bM=
12391241
github.com/hashicorp/vault/api v1.7.2/go.mod h1:xbfA+1AvxFseDzxxdWaL0uO99n1+tndus4GCrtouy0M=
12401242
github.com/hashicorp/vault/api v1.8.0/go.mod h1:uJrw6D3y9Rv7hhmS17JQC50jbPDAZdjZoTtrCCxxs7E=
1241-
github.com/hashicorp/vault/api v1.8.1 h1:bMieWIe6dAlqAAPReZO/8zYtXaWUg/21umwqGZpEjCI=
1242-
github.com/hashicorp/vault/api v1.8.1/go.mod h1:uJrw6D3y9Rv7hhmS17JQC50jbPDAZdjZoTtrCCxxs7E=
1243+
github.com/hashicorp/vault/api v1.9.3-0.20230628215639-3ca33976762c h1:JhuUjg3NzAQczN4/ji+JltY06545IAJI+djmdDBpHUo=
1244+
github.com/hashicorp/vault/api v1.9.3-0.20230628215639-3ca33976762c/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8=
12431245
github.com/hashicorp/vault/api/auth/approle v0.1.0/go.mod h1:mHOLgh//xDx4dpqXoq6tS8Ob0FoCFWLU2ibJ26Lfmag=
12441246
github.com/hashicorp/vault/api/auth/kubernetes v0.2.0/go.mod h1:2BKADs9mwqAycDK/6tiHRh2sX0SPnC0DN4wHjJoAirw=
12451247
github.com/hashicorp/vault/api/auth/userpass v0.1.0/go.mod h1:0orUbtkEwbEPmaQ+wvfrOddGBimLJnuN8A/J0PNfBks=
@@ -1996,6 +1998,7 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
19961998
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
19971999
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
19982000
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
2001+
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
19992002
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
20002003
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
20012004
golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -2023,8 +2026,8 @@ golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab/go.mod h1:IxCIyHEi3zRg3s0
20232026
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
20242027
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
20252028
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
2026-
golang.org/x/crypto v0.0.0-20221012134737-56aed061732a h1:NmSIgad6KjE6VvHciPZuNRTKxGhlPfD6OA87W/PLkqg=
2027-
golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
2029+
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
2030+
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
20282031
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
20292032
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
20302033
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -2156,6 +2159,7 @@ golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug
21562159
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
21572160
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
21582161
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
2162+
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
21592163
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
21602164
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
21612165
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=

helper/transport.go

+23-6
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@ package helper
77

88
import (
99
"bytes"
10+
"crypto/tls"
1011
"encoding/json"
12+
"fmt"
1113
"log"
1214
"net/http"
1315
"net/http/httputil"
1416
"os"
1517
"strconv"
1618
"strings"
19+
"sync"
1720

1821
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/logging"
1922
"github.com/hashicorp/vault/sdk/helper/salt"
@@ -29,7 +32,7 @@ const (
2932
EnvLogResponseBody = "TERRAFORM_VAULT_LOG_RESPONSE_BODY"
3033
)
3134

32-
// TransportOptions for transport.
35+
// TransportOptions for TransportWrapper.
3336
type TransportOptions struct {
3437
// HMACRequestHeaders ensure that any configured header's value is
3538
// never revealed during logging operations.
@@ -42,7 +45,7 @@ type TransportOptions struct {
4245
LogResponseBody bool
4346
}
4447

45-
// DefaultTransportOptions for setting up the HTTP transport wrapper.
48+
// DefaultTransportOptions for setting up the HTTP TransportWrapper wrapper.
4649
func DefaultTransportOptions() *TransportOptions {
4750
opts := &TransportOptions{
4851
HMACRequestHeaders: []string{
@@ -65,13 +68,27 @@ func DefaultTransportOptions() *TransportOptions {
6568
return opts
6669
}
6770

68-
type transport struct {
71+
type TransportWrapper struct {
6972
name string
7073
transport http.RoundTripper
7174
options *TransportOptions
75+
m sync.RWMutex
7276
}
7377

74-
func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
78+
func (t *TransportWrapper) SetTLSConfig(c *tls.Config) error {
79+
t.m.Lock()
80+
defer t.m.Unlock()
81+
transport, ok := t.transport.(*http.Transport)
82+
if !ok {
83+
return fmt.Errorf("type assertion failed for %T", t.transport)
84+
}
85+
86+
transport.TLSClientConfig = c
87+
88+
return nil
89+
}
90+
91+
func (t *TransportWrapper) RoundTrip(req *http.Request) (*http.Response, error) {
7592
if logging.IsDebugOrHigher() {
7693
var origHeaders http.Header
7794
if len(t.options.HMACRequestHeaders) > 0 && len(req.Header) > 0 {
@@ -118,8 +135,8 @@ func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
118135
return resp, nil
119136
}
120137

121-
func NewTransport(name string, t http.RoundTripper, opts *TransportOptions) *transport {
122-
return &transport{
138+
func NewTransport(name string, t http.RoundTripper, opts *TransportOptions) *TransportWrapper {
139+
return &TransportWrapper{
123140
name: name,
124141
transport: t,
125142
options: opts,

internal/provider/auth_azure_test.go

+15-3
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,11 @@ func TestAuthLoginAzure_LoginPath(t *testing.T) {
154154
func TestAuthLoginAzure_Login(t *testing.T) {
155155
handlerFunc := func(t *testLoginHandler, w http.ResponseWriter, req *http.Request) {
156156
m, err := json.Marshal(
157-
&api.Secret{},
157+
&api.Secret{
158+
Data: map[string]interface{}{
159+
"auth_login": "azure",
160+
},
161+
},
158162
)
159163
if err != nil {
160164
w.WriteHeader(http.StatusInternalServerError)
@@ -198,7 +202,11 @@ func TestAuthLoginAzure_Login(t *testing.T) {
198202
consts.FieldResourceGroupName: "res1",
199203
},
200204
},
201-
want: &api.Secret{},
205+
want: &api.Secret{
206+
Data: map[string]interface{}{
207+
"auth_login": "azure",
208+
},
209+
},
202210
wantErr: false,
203211
},
204212
{
@@ -225,7 +233,11 @@ func TestAuthLoginAzure_Login(t *testing.T) {
225233
skipFunc: func(t *testing.T) {
226234
testutil.SkipTestEnvUnset(t, envVarTFAccAzureAuth)
227235
},
228-
want: &api.Secret{},
236+
want: &api.Secret{
237+
Data: map[string]interface{}{
238+
"auth_login": "azure",
239+
},
240+
},
229241
wantErr: false,
230242
},
231243
{

internal/provider/auth_cert.go

+30-25
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44
package provider
55

66
import (
7+
"crypto/tls"
78
"fmt"
9+
"net/http"
810

911
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1012
"github.com/hashicorp/vault/api"
1113

14+
"github.com/hashicorp/terraform-provider-vault/helper"
1215
"github.com/hashicorp/terraform-provider-vault/internal/consts"
1316
)
1417

@@ -75,7 +78,11 @@ func (l *AuthLoginCert) LoginPath() string {
7578
}
7679

7780
func (l *AuthLoginCert) Init(d *schema.ResourceData, authField string) (AuthLogin, error) {
78-
if err := l.AuthLoginCommon.Init(d, authField); err != nil {
81+
if err := l.AuthLoginCommon.Init(d, authField,
82+
func(data *schema.ResourceData) error {
83+
return l.checkRequiredFields(d, consts.FieldCertFile, consts.FieldKeyFile)
84+
},
85+
); err != nil {
7986
return nil, err
8087
}
8188

@@ -111,46 +118,44 @@ func (l *AuthLoginCert) Login(client *api.Client) (*api.Secret, error) {
111118
return nil, err
112119
}
113120

114-
tlsConfig := &api.TLSConfig{
115-
Insecure: false,
116-
}
117-
118-
if v, ok := l.params[consts.FieldCACertFile]; ok {
119-
tlsConfig.CACert = v.(string)
120-
}
121-
122-
if v, ok := l.params[consts.FieldCACertDir]; ok {
123-
tlsConfig.CAPath = v.(string)
121+
config := client.CloneConfig()
122+
tlsConfig := config.TLSConfig()
123+
if tlsConfig == nil {
124+
return nil, fmt.Errorf("clone api.Config's TLSConfig is nil")
124125
}
125126

127+
var clientCertFile string
128+
var clientKeyFile string
126129
if v, ok := l.params[consts.FieldCertFile]; ok {
127-
tlsConfig.ClientCert = v.(string)
130+
clientCertFile = v.(string)
128131
}
129132

130133
if v, ok := l.params[consts.FieldKeyFile]; ok {
131-
tlsConfig.ClientKey = v.(string)
132-
}
133-
134-
if v, ok := l.params[consts.FieldTLSServerName]; ok {
135-
tlsConfig.TLSServerName = v.(string)
134+
clientKeyFile = v.(string)
136135
}
137136

138137
if v, ok := l.params[consts.FieldSkipTLSVerify]; ok {
139-
tlsConfig.Insecure = v.(bool)
138+
tlsConfig.InsecureSkipVerify = v.(bool)
140139
}
141140

142-
config := c.CloneConfig()
143-
if err := config.ConfigureTLS(tlsConfig); err != nil {
141+
clientCert, err := tls.LoadX509KeyPair(clientCertFile, clientKeyFile)
142+
if err != nil {
144143
return nil, err
145144
}
146145

147-
c, err = api.NewClient(config)
148-
if err != nil {
149-
return nil, err
146+
tlsConfig.GetClientCertificate = func(*tls.CertificateRequestInfo) (*tls.Certificate, error) {
147+
return &clientCert, nil
150148
}
151149

152-
if config.CloneHeaders {
153-
c.SetHeaders(client.Headers())
150+
switch t := config.HttpClient.Transport.(type) {
151+
case *helper.TransportWrapper:
152+
if err := t.SetTLSConfig(tlsConfig); err != nil {
153+
return nil, err
154+
}
155+
case *http.Transport:
156+
t.TLSClientConfig = tlsConfig
157+
default:
158+
return nil, fmt.Errorf("HTTPClient has unsupported Transport type %T", t)
154159
}
155160

156161
params := make(map[string]interface{})

internal/provider/auth_cert_test.go

+33-3
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@ import (
77
"encoding/json"
88
"fmt"
99
"net/http"
10+
"os"
11+
"path"
1012
"testing"
1113

1214
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1315
"github.com/hashicorp/vault/api"
1416

1517
"github.com/hashicorp/terraform-provider-vault/internal/consts"
18+
"github.com/hashicorp/terraform-provider-vault/testutil"
1619
)
1720

1821
func TestAuthLoginCert_Init(t *testing.T) {
@@ -207,13 +210,34 @@ func TestAuthLoginCert_Login(t *testing.T) {
207210
w.Write(m)
208211
}
209212

213+
tempDir := t.TempDir()
214+
215+
b, k, err := testutil.GenerateCA()
216+
if err != nil {
217+
t.Fatal(err)
218+
}
219+
220+
certFile := path.Join(tempDir, "cert.crt")
221+
if err := os.WriteFile(certFile, b, 0o400); err != nil {
222+
t.Fatal(err)
223+
}
224+
225+
keyFile := path.Join(tempDir, "cert.key")
226+
if err := os.WriteFile(keyFile, k, 0o400); err != nil {
227+
t.Fatal(err)
228+
}
229+
210230
tests := []authLoginTest{
211231
{
212232
name: "default",
213233
authLogin: &AuthLoginCert{
214234
AuthLoginCommon{
215-
authField: "baz",
216-
params: map[string]interface{}{},
235+
authField: "baz",
236+
params: map[string]interface{}{
237+
consts.FieldCertFile: certFile,
238+
consts.FieldKeyFile: keyFile,
239+
consts.FieldSkipTLSVerify: true,
240+
},
217241
initialized: true,
218242
},
219243
},
@@ -232,6 +256,7 @@ func TestAuthLoginCert_Login(t *testing.T) {
232256
},
233257
},
234258
},
259+
tls: true,
235260
wantErr: false,
236261
},
237262
{
@@ -241,7 +266,10 @@ func TestAuthLoginCert_Login(t *testing.T) {
241266
authField: "baz",
242267
mount: "qux",
243268
params: map[string]interface{}{
244-
consts.FieldName: "bob",
269+
consts.FieldName: "bob",
270+
consts.FieldCertFile: certFile,
271+
consts.FieldKeyFile: keyFile,
272+
consts.FieldSkipTLSVerify: true,
245273
},
246274
initialized: true,
247275
},
@@ -263,6 +291,7 @@ func TestAuthLoginCert_Login(t *testing.T) {
263291
},
264292
},
265293
},
294+
tls: true,
266295
wantErr: false,
267296
},
268297
{
@@ -277,6 +306,7 @@ func TestAuthLoginCert_Login(t *testing.T) {
277306
},
278307
want: nil,
279308
wantErr: true,
309+
tls: true,
280310
expectErr: authLoginInitCheckError,
281311
},
282312
}

internal/provider/auth_jwt_test.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,11 @@ func TestAuthLoginJWT_LoginPath(t *testing.T) {
108108
func TestAuthLoginJWT_Login(t *testing.T) {
109109
handlerFunc := func(t *testLoginHandler, w http.ResponseWriter, req *http.Request) {
110110
m, err := json.Marshal(
111-
&api.Secret{},
111+
&api.Secret{
112+
Data: map[string]interface{}{
113+
"auth_login": "jwt",
114+
},
115+
},
112116
)
113117
if err != nil {
114118
w.WriteHeader(http.StatusInternalServerError)
@@ -146,7 +150,11 @@ func TestAuthLoginJWT_Login(t *testing.T) {
146150
consts.FieldJWT: "jwt1",
147151
},
148152
},
149-
want: &api.Secret{},
153+
want: &api.Secret{
154+
Data: map[string]interface{}{
155+
"auth_login": "jwt",
156+
},
157+
},
150158
wantErr: false,
151159
},
152160
{

0 commit comments

Comments
 (0)