forked from istio/istio
-
Notifications
You must be signed in to change notification settings - Fork 1
/
authentication.go
204 lines (178 loc) · 6.66 KB
/
authentication.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
// Copyright 2018 Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import (
"fmt"
"net/url"
"strconv"
"github.com/envoyproxy/go-control-plane/envoy/api/v2/auth"
"github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
"github.com/envoyproxy/go-control-plane/envoy/config/grpc_credential/v2alpha"
"github.com/envoyproxy/go-control-plane/pkg/util"
"github.com/gogo/protobuf/proto"
"github.com/gogo/protobuf/types"
authn "istio.io/api/authentication/v1alpha1"
)
const (
// SDSStatPrefix is the human readable prefix to use when emitting statistics for the SDS service.
SDSStatPrefix = "sdsstat"
// SDSDefaultResourceName is the default name in sdsconfig, used for fetching normal key/cert.
SDSDefaultResourceName = "default"
// SDSRootResourceName is the sdsconfig name for root CA, used for fetching root cert.
SDSRootResourceName = "ROOTCA"
// K8sSAJwtTokenFileName is the token volume mount file name for k8s jwt token.
K8sSAJwtTokenFileName = "/var/run/secrets/tokens/istio-token"
// fileBasedMetadataPlugName is File Based Metadata credentials plugin name.
fileBasedMetadataPlugName = "envoy.grpc_credentials.file_based_metadata"
// k8sSAJwtTokenHeaderKey is the request header key for k8s jwt token.
// Binary header name must has suffix "-bin", according to https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md.
k8sSAJwtTokenHeaderKey = "istio_sds_credentials_header-bin"
)
// JwtKeyResolver resolves JWT public key and JwksURI.
var JwtKeyResolver = newJwksResolver(JwtPubKeyExpireDuration, JwtPubKeyEvictionDuration, JwtPubKeyRefreshInterval)
// GetConsolidateAuthenticationPolicy returns the authentication policy for
// service specified by hostname and port, if defined. It also tries to resolve JWKS URI if necessary.
func GetConsolidateAuthenticationPolicy(store IstioConfigStore, service *Service, port *Port) *authn.Policy {
config := store.AuthenticationPolicyByDestination(service, port)
if config != nil {
policy := config.Spec.(*authn.Policy)
if err := JwtKeyResolver.SetAuthenticationPolicyJwksURIs(policy); err == nil {
return policy
}
}
return nil
}
// ConstructSdsSecretConfig constructs SDS Sececret Configuration.
func ConstructSdsSecretConfig(name, sdsUdsPath, tokenMountFileName string, enableSdsTokenMount bool) *auth.SdsSecretConfig {
if name == "" || sdsUdsPath == "" {
return nil
}
gRPCConfig := &core.GrpcService_GoogleGrpc{
TargetUri: sdsUdsPath,
StatPrefix: SDSStatPrefix,
ChannelCredentials: &core.GrpcService_GoogleGrpc_ChannelCredentials{
CredentialSpecifier: &core.GrpcService_GoogleGrpc_ChannelCredentials_LocalCredentials{
LocalCredentials: &core.GrpcService_GoogleGrpc_GoogleLocalCredentials{},
},
},
}
if enableSdsTokenMount {
// If k8s sa jwt token volume mount file exists, envoy only handles plugin credentials.
tokenMountConfig := &v2alpha.FileBasedMetadataConfig{
SecretData: &core.DataSource{
Specifier: &core.DataSource_Filename{
Filename: tokenMountFileName,
},
},
HeaderKey: k8sSAJwtTokenHeaderKey,
}
gRPCConfig.CredentialsFactoryName = fileBasedMetadataPlugName
gRPCConfig.CallCredentials = []*core.GrpcService_GoogleGrpc_CallCredentials{
&core.GrpcService_GoogleGrpc_CallCredentials{
CredentialSpecifier: &core.GrpcService_GoogleGrpc_CallCredentials_FromPlugin{
FromPlugin: &core.GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin{
Name: fileBasedMetadataPlugName,
ConfigType: &core.GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin_Config{
protoToStruct(tokenMountConfig)},
},
},
},
}
} else {
gRPCConfig.CallCredentials = []*core.GrpcService_GoogleGrpc_CallCredentials{
&core.GrpcService_GoogleGrpc_CallCredentials{
CredentialSpecifier: &core.GrpcService_GoogleGrpc_CallCredentials_GoogleComputeEngine{
GoogleComputeEngine: &types.Empty{},
},
},
}
}
return &auth.SdsSecretConfig{
Name: name,
SdsConfig: &core.ConfigSource{
ConfigSourceSpecifier: &core.ConfigSource_ApiConfigSource{
ApiConfigSource: &core.ApiConfigSource{
ApiType: core.ApiConfigSource_GRPC,
GrpcServices: []*core.GrpcService{
{
TargetSpecifier: &core.GrpcService_GoogleGrpc_{
GoogleGrpc: gRPCConfig,
},
},
},
},
},
},
}
}
// ConstructValidationContext constructs ValidationContext in CommonTlsContext.
func ConstructValidationContext(rootCAFilePath string, subjectAltNames []string) *auth.CommonTlsContext_ValidationContext {
ret := &auth.CommonTlsContext_ValidationContext{
ValidationContext: &auth.CertificateValidationContext{
TrustedCa: &core.DataSource{
Specifier: &core.DataSource_Filename{
Filename: rootCAFilePath,
},
},
},
}
if len(subjectAltNames) > 0 {
ret.ValidationContext.VerifySubjectAltName = subjectAltNames
}
return ret
}
// ParseJwksURI parses the input URI and returns the corresponding hostname, port, and whether SSL is used.
// URI must start with "http://" or "https://", which corresponding to "http" or "https" scheme.
// Port number is extracted from URI if available (i.e from postfix :<port>, eg. ":80"), or assigned
// to a default value based on URI scheme (80 for http and 443 for https).
// Port name is set to URI scheme value.
// Note: this is to replace [buildJWKSURIClusterNameAndAddress]
// (https://github.com/istio/istio/blob/master/pilot/pkg/proxy/envoy/v1/mixer.go#L401),
// which is used for the old EUC policy.
func ParseJwksURI(jwksURI string) (string, *Port, bool, error) {
u, err := url.Parse(jwksURI)
if err != nil {
return "", nil, false, err
}
var useSSL bool
var portNumber int
switch u.Scheme {
case "http":
useSSL = false
portNumber = 80
case "https":
useSSL = true
portNumber = 443
default:
return "", nil, false, fmt.Errorf("URI scheme %q is not supported", u.Scheme)
}
if u.Port() != "" {
portNumber, err = strconv.Atoi(u.Port())
if err != nil {
return "", nil, useSSL, err
}
}
return u.Hostname(), &Port{
Name: u.Scheme,
Port: portNumber,
}, useSSL, nil
}
func protoToStruct(msg proto.Message) *types.Struct {
s, err := util.MessageToStruct(msg)
if err != nil {
log.Error(err.Error())
return &types.Struct{}
}
return s
}