in auth/auth.go [123:205]
func (c *Client) Token(ctx context.Context, cfg *config.MountConfig) (*oauth2.Token, error) {
var audience string
idPool, idProvider, err := c.gkeWorkloadIdentity(ctx, cfg)
if err != nil {
idPool, idProvider, audience, err = c.fleetWorkloadIdentity(ctx, cfg)
if err != nil {
return nil, err
}
}
if audience == "" {
audience = fmt.Sprintf("identitynamespace:%s:%s", idPool, idProvider)
klog.V(5).InfoS("workload id configured", "pool", idPool, "provider", idProvider)
} else {
klog.V(5).InfoS("workload federation pool audience", audience)
}
// Get iam.gke.io/gcp-service-account annotation to see if the
// identitybindingtoken token should be traded for a GCP SA token.
// See https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity#creating_a_relationship_between_ksas_and_gsas
saResp, err := c.KubeClient.
CoreV1().
ServiceAccounts(cfg.PodInfo.Namespace).
Get(ctx, cfg.PodInfo.ServiceAccount, v1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("unable to fetch SA info: %w", err)
}
gcpSA := saResp.Annotations["iam.gke.io/gcp-service-account"]
klog.V(5).InfoS("matched service account", "service_account", gcpSA)
// Obtain a serviceaccount token for the pod.
var saTokenVal string
if cfg.PodInfo.ServiceAccountTokens != "" {
saToken, err := c.extractSAToken(cfg, idPool, audience) // calling function to extract token received from driver.
if err != nil {
return nil, fmt.Errorf("unable to fetch SA token from driver: %w", err)
}
saTokenVal = saToken.Token
} else {
saToken, err := c.generatePodSAToken(ctx, cfg, idPool, audience) // if no token received, provider generates its own token.
if err != nil {
return nil, fmt.Errorf("unable to fetch pod token: %w", err)
}
saTokenVal = saToken.Token
}
// Trade the kubernetes token for an identitybindingtoken token.
idBindToken, err := tradeIDBindToken(ctx, c.HTTPClient, saTokenVal, audience)
if err != nil {
return nil, fmt.Errorf("unable to fetch identitybindingtoken: %w", err)
}
// If no `iam.gke.io/gcp-service-account` annotation is present the
// identitybindingtoken will be used directly, allowing bindings on secrets
// of the form "serviceAccount:<project>.svc.id.goog[<namespace>/<sa>]".
if gcpSA == "" {
return idBindToken, nil
}
req := &credentialspb.GenerateAccessTokenRequest{
Name: fmt.Sprintf("projects/-/serviceAccounts/%s", gcpSA),
Scope: secretmanager.DefaultAuthScopes(),
}
if gcpSADelegates, ok := saResp.Annotations["iam.gke.io/gcp-service-account-delegates"]; ok {
var delegates []string
if err := json.Unmarshal([]byte(gcpSADelegates), &delegates); err != nil {
return nil, fmt.Errorf("unable to parse delegates annotation on SA: %w", err)
}
klog.V(5).InfoS("matched service account delegates", "service_account_delegates", delegates)
for _, delegate := range delegates {
req.Delegates = append(req.Delegates, fmt.Sprintf("projects/-/serviceAccounts/%s", delegate))
}
}
gcpSAResp, err := c.IAMClient.GenerateAccessToken(ctx, req, gax.WithGRPCOptions(grpc.PerRPCCredentials(oauth.TokenSource{TokenSource: oauth2.StaticTokenSource(idBindToken)})))
if err != nil {
return nil, fmt.Errorf("unable to fetch gcp service account token: %w", err)
}
return &oauth2.Token{AccessToken: gcpSAResp.GetAccessToken()}, nil
}