gRPC ALTS (Application Layer Transport Security) implementation for secure and authenticated communication between Google Cloud VMs
—
Runtime context access for service identity verification and authorization checks in ALTS-secured gRPC communications.
Provides access to ALTS authentication context information including peer service accounts and security levels.
/**
* Contains ALTS authentication context information
*/
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/7864")
public final class AltsContext {
/**
* Creates a test instance of AltsContext for testing purposes
* @param peerServiceAccount the peer service account
* @param localServiceAccount the local service account
* @return AltsContext test instance
*/
public static AltsContext createTestInstance(String peerServiceAccount, String localServiceAccount);
/**
* Returns the security level of this context
* @return the SecurityLevel
*/
public SecurityLevel getSecurityLevel();
/**
* Returns the peer service account from the ALTS handshake
* @return the peer service account string
*/
public String getPeerServiceAccount();
/**
* Returns the local service account from the ALTS handshake
* @return the local service account string
*/
public String getLocalServiceAccount();
/**
* Security levels supported by ALTS
*/
public enum SecurityLevel {
/** Unknown security level */
UNKNOWN,
/** No security applied */
SECURITY_NONE,
/** Integrity protection only */
INTEGRITY_ONLY,
/** Both integrity and privacy protection */
INTEGRITY_AND_PRIVACY
}
}Usage Examples:
import io.grpc.alts.AltsContext;
import io.grpc.alts.AltsContextUtil;
import io.grpc.ServerCall;
// In a server interceptor or service method
public void handleRequest(ServerCall<?, ?> call) {
if (AltsContextUtil.check(call)) {
AltsContext context = AltsContextUtil.createFrom(call);
String peerAccount = context.getPeerServiceAccount();
String localAccount = context.getLocalServiceAccount();
AltsContext.SecurityLevel level = context.getSecurityLevel();
System.out.println("Peer: " + peerAccount);
System.out.println("Local: " + localAccount);
System.out.println("Security: " + level);
// Verify expected peer
if ("expected-client@project.iam.gserviceaccount.com".equals(peerAccount)) {
// Process request
} else {
// Reject request
}
}
}
// Testing context
AltsContext testContext = AltsContext.createTestInstance(
"test-peer@project.iam.gserviceaccount.com",
"test-local@project.iam.gserviceaccount.com"
);Utility methods for extracting and checking ALTS context from gRPC calls.
/**
* Utility methods for working with ALTS context
*/
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/7864")
public final class AltsContextUtil {
/**
* Creates AltsContext from a server call
* @param call the server call
* @return AltsContext or null if not available
*/
public static AltsContext createFrom(ServerCall<?, ?> call);
/**
* Creates AltsContext from a client call
* @param call the client call
* @return AltsContext or null if not available
*/
public static AltsContext createFrom(ClientCall<?, ?> call);
/**
* Creates AltsContext from transport attributes
* @param attributes the transport attributes
* @return AltsContext or null if not available
*/
public static AltsContext createFrom(Attributes attributes);
/**
* Checks if a server call contains ALTS information
* @param call the server call
* @return true if ALTS context is available
*/
public static boolean check(ServerCall<?, ?> call);
/**
* Checks if a client call contains ALTS information
* @param call the client call
* @return true if ALTS context is available
*/
public static boolean check(ClientCall<?, ?> call);
/**
* Checks if transport attributes contain ALTS information
* @param attributes the transport attributes
* @return true if ALTS context is available
*/
public static boolean check(Attributes attributes);
}Usage Examples:
import io.grpc.alts.AltsContextUtil;
import io.grpc.alts.AltsContext;
import io.grpc.ServerCall;
import io.grpc.ClientCall;
import io.grpc.Attributes;
// Server-side context extraction
public class AltsServerInterceptor implements ServerInterceptor {
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
ServerCall<ReqT, RespT> call,
Metadata headers,
ServerCallHandler<ReqT, RespT> next) {
if (AltsContextUtil.check(call)) {
AltsContext context = AltsContextUtil.createFrom(call);
if (context != null) {
// Log or validate the peer service account
System.out.println("ALTS peer: " + context.getPeerServiceAccount());
}
} else {
System.out.println("No ALTS context available");
}
return next.startCall(call, headers);
}
}
// Client-side context extraction
public class AltsClientInterceptor implements ClientInterceptor {
@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> method,
CallOptions callOptions,
Channel next) {
ClientCall<ReqT, RespT> call = next.newCall(method, callOptions);
// Check context after call completion
if (AltsContextUtil.check(call)) {
AltsContext context = AltsContextUtil.createFrom(call);
if (context != null) {
System.out.println("Server identity: " + context.getPeerServiceAccount());
}
}
return call;
}
}
// Transport attributes context extraction
public void handleTransportReady(Attributes attributes) {
if (AltsContextUtil.check(attributes)) {
AltsContext context = AltsContextUtil.createFrom(attributes);
if (context != null) {
System.out.println("Transport secured with ALTS");
System.out.println("Security level: " + context.getSecurityLevel());
}
}
}Utility methods for performing authorization checks based on ALTS context.
/**
* Utility methods for ALTS-based authorization
*/
public final class AuthorizationUtil {
/**
* Performs client authorization check against expected service accounts
* @param call the server call to check
* @param expectedServiceAccounts collection of expected service accounts
* @return Status.OK if authorized, error status otherwise
*/
public static Status clientAuthorizationCheck(
ServerCall<?, ?> call,
Collection<String> expectedServiceAccounts
);
}Usage Examples:
import io.grpc.alts.AuthorizationUtil;
import io.grpc.ServerCall;
import io.grpc.Status;
import java.util.Arrays;
import java.util.Collection;
// Server-side authorization
public class AuthorizingServiceImpl extends MyServiceGrpc.MyServiceImplBase {
private static final Collection<String> ALLOWED_CLIENTS = Arrays.asList(
"frontend@my-project.iam.gserviceaccount.com",
"batch-processor@my-project.iam.gserviceaccount.com"
);
@Override
public void myMethod(MyRequest request, StreamObserver<MyResponse> responseObserver) {
// Get the current server call
ServerCall<?, ?> call = getCurrentCall(); // Implementation-specific
// Perform authorization check
Status authStatus = AuthorizationUtil.clientAuthorizationCheck(call, ALLOWED_CLIENTS);
if (!authStatus.isOk()) {
responseObserver.onError(authStatus.asRuntimeException());
return;
}
// Process authorized request
MyResponse response = processRequest(request);
responseObserver.onNext(response);
responseObserver.onCompleted();
}
}
// Authorization in a server interceptor
public class AuthorizationInterceptor implements ServerInterceptor {
private final Collection<String> allowedServiceAccounts;
public AuthorizationInterceptor(Collection<String> allowedServiceAccounts) {
this.allowedServiceAccounts = allowedServiceAccounts;
}
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
ServerCall<ReqT, RespT> call,
Metadata headers,
ServerCallHandler<ReqT, RespT> next) {
Status authStatus = AuthorizationUtil.clientAuthorizationCheck(call, allowedServiceAccounts);
if (!authStatus.isOk()) {
call.close(authStatus, new Metadata());
return new ServerCall.Listener<ReqT>() {};
}
return next.startCall(call, headers);
}
}Common pattern for accessing security context in service implementations:
import io.grpc.alts.AltsContextUtil;
import io.grpc.alts.AltsContext;
import io.grpc.stub.StreamObserver;
public class SecureServiceImpl extends MyServiceGrpc.MyServiceImplBase {
@Override
public void secureMethod(MyRequest request, StreamObserver<MyResponse> responseObserver) {
// Access current call context
ServerCall<?, ?> call = getCurrentServerCall();
if (AltsContextUtil.check(call)) {
AltsContext altsContext = AltsContextUtil.createFrom(call);
// Use context for logging, authorization, or business logic
String clientServiceAccount = altsContext.getPeerServiceAccount();
AltsContext.SecurityLevel securityLevel = altsContext.getSecurityLevel();
// Log security information
System.out.printf("Request from %s with security level %s%n",
clientServiceAccount, securityLevel);
// Implement business logic with identity awareness
MyResponse response = handleSecureRequest(request, clientServiceAccount);
responseObserver.onNext(response);
responseObserver.onCompleted();
} else {
responseObserver.onError(
Status.UNAUTHENTICATED
.withDescription("ALTS authentication required")
.asRuntimeException()
);
}
}
private ServerCall<?, ?> getCurrentServerCall() {
// Implementation depends on how you access the current call
// This might involve ThreadLocal, Context propagation, or dependency injection
return null; // Placeholder
}
}AuthorizationUtil for consistent authorization checksAltsContext.createTestInstance() only in test environmentsInstall with Tessl CLI
npx tessl i tessl/maven-io-grpc--grpc-alts