Hi,
we recently started to try out ALTS in our GCP environment with two grpc services written in Go.
We successfully could bootstrap our setup with the examples provided in [1]
.From our experience ALTS is very handy and works as expected. Because we are fully in GCP ALTS is currently internally discussed to replace TLS as a whole.
But we have notice a unexpected behavior during our work with ALTS. We have a GKE cluster where we have enabled Workload identity [2].
We have created a pod with a Kubernetes service account (KSA) and bound it to a Google service account (GSA) via an IAM policy described in the docs.
In general when ever the pod talks to a GCP API the pod authenticates with the GSA. But we have noticed that a service with ALTS server retrieves not the GSA but
the service account of the underlying compute instance which is quite unfortunate because this means that all pod in a GKE cluster share the same identity.
Our test setup is pasted below. We have basically wrapped alts.NewServerCreds to log out the field of alts.AuthInfo what we get in the logs are:
2020-03-24 12:34:17.000 CET { "msg": "ATLS server AuthInfo. PeerServiceAccount: k8s-main@<omitted>.
iam.gserviceaccount.com", "level": "info" }
2020-03-24 12:34:17.000 CET { "msg": "ATLS server AuthInfo. LocalServiceAccount: k8s-test@<omitted>.
iam.gserviceaccount.com", "level": "info" }
Just to be clear the service accounts in the logs (k8s-main and k8s-test) are the GCE service account and the pod has a totally different GSA via workload identity.
We understand that ALTS does not have a stable API yet but because of this we would appreciate of you could consider support workload identity of GKE in the future.
This would give ALTS a much bigger user case for a lot of GCP users.
And speaking of officially releasing a stable ALTS API are there any plans or timelines for that yet?
Thanks,
Mahmoud Azad
Appendix: Test code
func setupALTSGrpcCreds() grpc.ServerOption {
serverCreds := alts.NewServerCreds(alts.DefaultServerOptions())
wrappedTransportCredentials := transportCredsWrapper{wrapped: serverCreds}
return grpc.Creds(wrappedTransportCredentials)
type transportCredsWrapper struct {
wrapped credentials.TransportCredentials
}
func (t transportCredsWrapper) ClientHandshake(ctx context.Context, addr string, rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) {
return t.wrapped.ClientHandshake(ctx, addr, rawConn)
}
func (t transportCredsWrapper) ServerHandshake(rawConn net.Conn) (net.Conn, credentials.AuthInfo, error) {
con, authInfo, err := t.wrapped.ServerHandshake(rawConn)
if err != nil {
log.Warnf("got error in transportCredsWrapper: %s", err)
return nil, nil, err
}
altsAuthInfo, ok := authInfo.(alts.AuthInfo)
if !ok {
return nil, nil, errors.New("server-side auth info is not of type alts.AuthInfo")
}
log.Infof("ATLS server AuthInfo. LocalServiceAccount: %s", altsAuthInfo.LocalServiceAccount())
log.Infof("ATLS server AuthInfo. PeerServiceAccount: %s", altsAuthInfo.PeerServiceAccount())
return con, authInfo, err
}
[...]
On Tuesday, 21 January 2020 18:54:18 UTC+1, Cyrus Katrak wrote:Thanks.