istio

Форк
0
164 строки · 4.9 Кб
1
// Copyright Istio Authors
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
package caclient
16

17
import (
18
	"context"
19
	"crypto/tls"
20
	"crypto/x509"
21
	"errors"
22
	"fmt"
23
	"regexp"
24
	"strings"
25

26
	"github.com/google/uuid"
27
	"google.golang.org/grpc"
28
	"google.golang.org/grpc/credentials"
29
	"google.golang.org/grpc/credentials/insecure"
30
	"google.golang.org/grpc/metadata"
31
	"google.golang.org/protobuf/types/known/durationpb"
32

33
	"istio.io/istio/pkg/bootstrap/platform"
34
	"istio.io/istio/pkg/env"
35
	"istio.io/istio/pkg/log"
36
	sec_model "istio.io/istio/pkg/model"
37
	"istio.io/istio/pkg/security"
38
	"istio.io/istio/security/pkg/nodeagent/caclient"
39
	gcapb "istio.io/istio/security/proto/providers/google"
40
)
41

42
const hubIDPPrefix = "https://gkehub.googleapis.com/"
43

44
var (
45
	googleCAClientLog = log.RegisterScope("googleca", "Google CA client debugging")
46
	envGkeClusterURL  = env.Register("GKE_CLUSTER_URL", "", "The url of GKE cluster").Get()
47
)
48

49
type googleCAClient struct {
50
	caEndpoint string
51
	enableTLS  bool
52
	client     gcapb.MeshCertificateServiceClient
53
	conn       *grpc.ClientConn
54
}
55

56
// NewGoogleCAClient create a CA client for Google CA.
57
func NewGoogleCAClient(endpoint string, tls bool, provider *caclient.TokenProvider) (security.Client, error) {
58
	c := &googleCAClient{
59
		caEndpoint: endpoint,
60
		enableTLS:  tls,
61
	}
62

63
	var opts grpc.DialOption
64
	var err error
65
	if tls {
66
		opts, err = c.getTLSDialOption()
67
		if err != nil {
68
			return nil, err
69
		}
70
	} else {
71
		opts = grpc.WithTransportCredentials(insecure.NewCredentials())
72
	}
73

74
	conn, err := grpc.Dial(endpoint,
75
		opts,
76
		grpc.WithPerRPCCredentials(provider),
77
		security.CARetryInterceptor(),
78
	)
79
	if err != nil {
80
		googleCAClientLog.Errorf("Failed to connect to endpoint %s: %v", endpoint, err)
81
		return nil, fmt.Errorf("failed to connect to endpoint %s", endpoint)
82
	}
83

84
	c.conn = conn
85
	c.client = gcapb.NewMeshCertificateServiceClient(conn)
86
	return c, nil
87
}
88

89
// CSR Sign calls Google CA to sign a CSR.
90
func (cl *googleCAClient) CSRSign(csrPEM []byte, certValidTTLInSec int64) ([]string, error) {
91
	req := &gcapb.MeshCertificateRequest{
92
		RequestId: uuid.New().String(),
93
		Csr:       string(csrPEM),
94
		Validity:  &durationpb.Duration{Seconds: certValidTTLInSec},
95
	}
96

97
	out := metadata.New(nil)
98
	gkeClusterURL := envGkeClusterURL
99
	if envGkeClusterURL == "" && platform.IsGCP() {
100
		gkeClusterURL = platform.NewGCP().Metadata()[platform.GCPClusterURL]
101
	}
102
	zone := parseZone(gkeClusterURL)
103
	if zone != "" {
104
		out["x-goog-request-params"] = []string{fmt.Sprintf("location=locations/%s", zone)}
105
	}
106

107
	ctx := metadata.NewOutgoingContext(context.Background(), out)
108
	resp, err := cl.client.CreateCertificate(ctx, req)
109
	if err != nil {
110
		googleCAClientLog.Errorf("Failed to create certificate: %v", err)
111
		googleCAClientLog.Debugf("Original request %v, resp %v", req, resp)
112
		return nil, err
113
	}
114

115
	if len(resp.CertChain) <= 1 {
116
		googleCAClientLog.Errorf("CertChain length is %d, expected more than 1", len(resp.CertChain))
117
		return nil, errors.New("invalid response cert chain")
118
	}
119
	googleCAClientLog.Infof("Cert created with GoogleCA %s chain length %d", zone, len(resp.CertChain))
120

121
	return resp.CertChain, nil
122
}
123

124
func (cl *googleCAClient) Close() {
125
	if cl.conn != nil {
126
		err := cl.conn.Close()
127
		if err != nil {
128
			googleCAClientLog.Infof("CAClient Connection is not closed: %v", err)
129
		}
130
	}
131
}
132

133
func (cl *googleCAClient) getTLSDialOption() (grpc.DialOption, error) {
134
	// Load the system default root certificates.
135
	pool, err := x509.SystemCertPool()
136
	if err != nil {
137
		googleCAClientLog.Errorf("could not get SystemCertPool: %v", err)
138
		return nil, errors.New("could not get SystemCertPool")
139
	}
140
	tlsConfig := &tls.Config{MinVersion: tls.VersionTLS12, RootCAs: pool}
141
	sec_model.EnforceGoCompliance(tlsConfig)
142
	creds := credentials.NewTLS(tlsConfig)
143
	return grpc.WithTransportCredentials(creds), nil
144
}
145

146
// GetRootCertBundle: Google Mesh CA doesn't publish any endpoint to retrieve CA certs
147
func (cl *googleCAClient) GetRootCertBundle() ([]string, error) {
148
	return []string{}, nil
149
}
150

151
func parseZone(clusterURL string) string {
152
	// for Hub IDNS, the input is https://gkehub.googleapis.com/projects/HUB_PROJECT_ID/locations/global/memberships/MEMBERSHIP_ID which is global
153
	if strings.HasPrefix(clusterURL, hubIDPPrefix) {
154
		return ""
155
	}
156
	// input: https://container.googleapis.com/v1/projects/testproj/locations/us-central1-c/clusters/cluster1
157
	// output: us-central1-c
158
	rgx := regexp.MustCompile(`.*/projects/(.*)/locations/(.*)/clusters/.*`)
159
	rs := rgx.FindStringSubmatch(clusterURL)
160
	if len(rs) < 3 {
161
		return ""
162
	}
163
	return rs[2]
164
}
165

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.