Skip to content

Commit 726f4a5

Browse files
ryysudazdagron
authored andcommitted
Detect misconfiguration of bundle_endpoint_profile (spiffe#3395)
* Detect misconfiguration of bundle_endpoint_profile Signed-off-by: Ryuma Yoshida <[email protected]> Co-authored-by: Andrew Harding <[email protected]>
1 parent 0e43615 commit 726f4a5

File tree

2 files changed

+53
-10
lines changed

2 files changed

+53
-10
lines changed

pkg/server/bundle/client/client.go

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package client
33
import (
44
"context"
55
"crypto/x509"
6+
"errors"
67
"fmt"
78
"io"
89
"net/http"
@@ -35,6 +36,10 @@ type ClientConfig struct { //revive:disable-line:exported name stutter is intent
3536
// using SPIFFE authentication. If unset, it is assumed that the endpoint
3637
// is authenticated via Web PKI.
3738
SPIFFEAuth *SPIFFEAuthConfig
39+
40+
// mutateTransportHook is a hook to influence the transport used during
41+
// tests.
42+
mutateTransportHook func(*http.Transport)
3843
}
3944

4045
// Client is used to fetch a bundle and metadata from a bundle endpoint
@@ -48,7 +53,7 @@ type client struct {
4853
}
4954

5055
func NewClient(config ClientConfig) (Client, error) {
51-
httpClient := &http.Client{}
56+
transport := newTransport()
5257
if config.SPIFFEAuth != nil {
5358
endpointID := config.SPIFFEAuth.EndpointSpiffeID
5459
if endpointID.IsZero() {
@@ -59,19 +64,26 @@ func NewClient(config ClientConfig) (Client, error) {
5964

6065
authorizer := tlsconfig.AuthorizeID(endpointID)
6166

62-
httpClient.Transport = &http.Transport{
63-
TLSClientConfig: tlsconfig.TLSClientConfig(bundle, authorizer),
64-
}
67+
transport.TLSClientConfig = tlsconfig.TLSClientConfig(bundle, authorizer)
68+
}
69+
if config.mutateTransportHook != nil {
70+
config.mutateTransportHook(transport)
6571
}
6672
return &client{
6773
c: config,
68-
client: httpClient,
74+
client: &http.Client{Transport: transport},
6975
}, nil
7076
}
7177

7278
func (c *client) FetchBundle(ctx context.Context) (*bundleutil.Bundle, error) {
7379
resp, err := c.client.Get(c.c.EndpointURL)
7480
if err != nil {
81+
var hostnameError x509.HostnameError
82+
if errors.As(err, &hostnameError) && c.c.SPIFFEAuth == nil && len(hostnameError.Certificate.URIs) > 0 {
83+
if id, idErr := spiffeid.FromString(hostnameError.Certificate.URIs[0].String()); idErr == nil {
84+
return nil, errs.New("failed to authenticate bundle endpoint using web authentication but the server certificate contains SPIFFE ID %q: maybe use https_spiffe instead of https_web: %v", id, err)
85+
}
86+
}
7587
return nil, errs.New("failed to fetch bundle: %v", err)
7688
}
7789
defer resp.Body.Close()
@@ -93,3 +105,7 @@ func tryRead(r io.Reader) string {
93105
n, _ := r.Read(b)
94106
return string(b[:n])
95107
}
108+
109+
func newTransport() *http.Transport {
110+
return http.DefaultTransport.(*http.Transport).Clone()
111+
}

pkg/server/bundle/client/client_test.go

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"crypto/x509"
88
"fmt"
99
"math/big"
10-
"net"
1110
"net/http"
1211
"net/http/httptest"
1312
"net/url"
@@ -33,6 +32,8 @@ func TestClient(t *testing.T) {
3332
body string
3433
newClientErr string
3534
fetchBundleErr string
35+
useWebAuth bool
36+
mutateConfig func(*ClientConfig)
3637
}{
3738
{
3839
name: "success",
@@ -73,6 +74,18 @@ func TestClient(t *testing.T) {
7374
expectedID: serverID,
7475
fetchBundleErr: "failed to decode bundle",
7576
},
77+
{
78+
name: "hostname validation fails",
79+
status: http.StatusOK,
80+
body: "NOT JSON",
81+
serverID: serverID,
82+
expectedID: serverID,
83+
fetchBundleErr: "failed to authenticate bundle endpoint using web authentication but the server certificate contains SPIFFE ID \"spiffe://domain.test/spiffe-bundle-endpoint-server\": maybe use https_spiffe instead of https_web:",
84+
useWebAuth: true,
85+
mutateConfig: func(c *ClientConfig) {
86+
c.SPIFFEAuth = nil
87+
},
88+
},
7689
}
7790

7891
for _, testCase := range testCases {
@@ -96,14 +109,30 @@ func TestClient(t *testing.T) {
96109
server.StartTLS()
97110
defer server.Close()
98111

99-
client, err := NewClient(ClientConfig{
112+
var mutateTransportHook func(*http.Transport)
113+
if testCase.useWebAuth {
114+
mutateTransportHook = func(transport *http.Transport) {
115+
rootCAs := x509.NewCertPool()
116+
rootCAs.AddCert(serverCert)
117+
transport.TLSClientConfig = &tls.Config{RootCAs: rootCAs, MinVersion: tls.VersionTLS12}
118+
}
119+
}
120+
121+
config := ClientConfig{
100122
TrustDomain: trustDomain,
101123
EndpointURL: server.URL,
102124
SPIFFEAuth: &SPIFFEAuthConfig{
103125
EndpointSpiffeID: testCase.expectedID,
104126
RootCAs: []*x509.Certificate{serverCert},
105127
},
106-
})
128+
mutateTransportHook: mutateTransportHook,
129+
}
130+
131+
if testCase.mutateConfig != nil {
132+
testCase.mutateConfig(&config)
133+
}
134+
135+
client, err := NewClient(config)
107136
if testCase.newClientErr != "" {
108137
require.Error(t, err)
109138
require.Contains(t, err.Error(), testCase.newClientErr)
@@ -128,8 +157,6 @@ func TestClient(t *testing.T) {
128157
func createServerCertificate(t *testing.T, serverID spiffeid.ID) (*x509.Certificate, crypto.Signer) {
129158
return spiretest.SelfSignCertificate(t, &x509.Certificate{
130159
SerialNumber: big.NewInt(0),
131-
DNSNames: []string{"localhost"},
132-
IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1)},
133160
NotAfter: time.Now().Add(time.Hour),
134161
URIs: []*url.URL{serverID.URL()},
135162
})

0 commit comments

Comments
 (0)