1
// Copyright Istio Authors
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
7
// http://www.apache.org/licenses/LICENSE-2.0
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.
22
"google.golang.org/grpc/credentials"
24
"istio.io/istio/pkg/security"
25
"istio.io/istio/security/pkg/nodeagent/plugin/providers/google/stsclient"
26
"istio.io/istio/security/pkg/stsservice"
27
"istio.io/istio/security/pkg/stsservice/server"
28
"istio.io/istio/security/pkg/stsservice/tokenmanager/google"
31
// TokenProvider is a grpc PerRPCCredentials that can be used to attach a JWT token to each gRPC call.
32
// TokenProvider can be used for XDS, which may involve token exchange through STS.
33
type TokenProvider struct {
34
opts *security.Options
35
// TokenProvider can be used for XDS. Because CA is often used with
36
// external systems and XDS is not often (yet?), many of the security options only apply to CA
37
// communication. A more proper solution would be to have separate options for CA and XDS, but
38
// this requires API changes.
42
var _ credentials.PerRPCCredentials = &TokenProvider{}
46
func NewCATokenProvider(opts *security.Options) *TokenProvider {
47
return &TokenProvider{opts, true}
50
func NewXDSTokenProvider(opts *security.Options) *TokenProvider {
51
return &TokenProvider{opts, false}
54
func (t *TokenProvider) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
58
token, err := t.GetToken()
65
if t.opts.TokenManager == nil {
66
return map[string]string{
67
"authorization": "Bearer " + token,
70
return t.opts.TokenManager.GetMetadata(t.forCA, t.opts.XdsAuthProvider, token)
73
// Allow the token provider to be used regardless of transport security; callers can determine whether
74
// this is safe themselves.
75
func (t *TokenProvider) RequireTransportSecurity() bool {
79
// GetToken fetches a token to attach to a request. Returning "", nil will cause no header to be
80
// added; while a non-nil error will block the request If the token selected is not found, no error
81
// will be returned, causing no authorization header to be set. This ensures that even if the JWT
82
// token is missing (for example, on a VM that has rebooted, causing the token to be removed from
83
// volatile memory), we can still proceed and allow other authentication methods to potentially
84
// handle the request, such as mTLS.
85
func (t *TokenProvider) GetToken() (string, error) {
86
if t.opts.CredFetcher == nil {
89
token, err := t.opts.CredFetcher.GetPlatformCredential()
91
return "", fmt.Errorf("fetch platform credential: %v", err)
94
// Regardless of where the token came from, we (optionally) can exchange the token for a different
96
return t.exchangeCAToken(token)
98
return t.exchangeXDSToken(token)
101
// exchangeCAToken exchanges the provided token using TokenExchanger, if configured. If not, the
102
// original token is returned.
103
func (t *TokenProvider) exchangeCAToken(token string) (string, error) {
104
if t.opts.TokenExchanger == nil {
107
return t.opts.TokenExchanger.ExchangeToken(token)
110
func (t *TokenProvider) exchangeXDSToken(token string) (string, error) {
111
if t.opts.XdsAuthProvider != google.GCPAuthProvider {
115
// For XDS flow, the token exchange is different from that of the CA flow.
116
if t.opts.TokenManager == nil {
117
return "", fmt.Errorf("XDS token exchange is enabled but token manager is nil")
120
return "", fmt.Errorf("the token for XDS token exchange is empty")
122
params := security.StsRequestParameters{
123
Scope: stsclient.Scope,
124
GrantType: server.TokenExchangeGrantType,
126
SubjectTokenType: server.SubjectTokenType,
128
body, err := t.opts.TokenManager.GenerateToken(params)
130
return "", fmt.Errorf("token manager failed to generate access token: %v", err)
132
respData := &stsservice.StsResponseParameters{}
133
if err := json.Unmarshal(body, respData); err != nil {
134
return "", fmt.Errorf("failed to unmarshal access token response data: %v", err)
136
return respData.AccessToken, nil