Go gRPC advanced-TLS authentication + custom method authentication (7)

Foreword

The gRPCs in the previous chapter are all transmitted in clear text, which is easy to be tampered with data. This chapter will introduce how to add security mechanism to gRPC, including TLS certificate authentication and Token authentication.

TLS certificate authentication

What is TLS

TLS (Transport Layer Security). TLS is a 传输层protocol built on the TCP protocol and serves the application layer. Its predecessor is SSL (Secure Socket Layer), which implements the application layer After encrypting the message, it will be transferred to TCP for transmission.

The role of TLS

The TLS protocol mainly solves the following three network security issues.

  • Confidentiality (message privacy), confidentiality is achieved through encrypted encryption, all information is encrypted and transmitted, and third parties cannot sniff;
  • Message integrity, through the MAC verification mechanism, once tampered, both parties will immediately discover;
  • Mutual authentication, mutual authentication, both parties can be equipped with certificates to prevent identity being impersonated;

Generate private key

Generate RSA private key:openssl genrsa -out server.key 2048

Generate the RSA private key. The last parameter of the command will specify the number of bits to generate the key. If not specified, the default is 512

Generate ECC private key:openssl ecparam -genkey -name secp384r1 -out server.key

Generate the ECC private key, the command is the elliptic curve key parameter generation and operation

Generate public key

openssl req -new -x509 -sha256 -key server.key -out server.pem -days 3650

openssl req: Generate a self-signed certificate, -new means to generate a certificate request, -sha256 means to use sha256 encryption, -key to specify the private key file, -x509 means to output the certificate, -days 3650 is the validity period

After that, enter the certificate owner information

Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:XxXx
Locality Name (eg, city) []:XxXx
Organization Name (eg, company) [Internet Widgits Pty Ltd]:XX Co. Ltd
Organizational Unit Name (eg, section) []:Dev
Common Name (e.g. server FQDN or YOUR name) []:go-grpc-example
Email Address []:[email protected]

The server builds a TLS certificate and certifies

func main() {
	// 监听本地端口
	listener, err := net.Listen(Network, Address)
	if err != nil {
		log.Fatalf("net.Listen err: %v", err)
	}
	// 从输入证书文件和密钥文件为服务端构造TLS凭证
	creds, err := credentials.NewServerTLSFromFile("../pkg/tls/server.pem", "../pkg/tls/server.key")
	if err != nil {
		log.Fatalf("Failed to generate credentials %v", err)
	}
	// 新建gRPC服务器实例,并开启TLS认证
	grpcServer := grpc.NewServer(grpc.Creds(creds))
	// 在gRPC服务器注册我们的服务
	pb.RegisterSimpleServer(grpcServer, &SimpleService{})
	log.Println(Address + " net.Listing whth TLS and token...")
	//用服务器 Serve() 方法以及我们的端口信息区实现阻塞等待,直到进程被杀死或者 Stop() 被调用
	err = grpcServer.Serve(listener)
	if err != nil {
		log.Fatalf("grpcServer.Serve err: %v", err)
	}
}
  • credentials.NewServerTLSFromFile: Construct a TLS certificate for the server from the input certificate file and key file
  • grpc.Creds: Return a ServerOption to set the credentials for server connection.

Complete server.go code

Client configures TLS connection

var grpcClient pb.SimpleClient

func main() {
	//从输入的证书文件中为客户端构造TLS凭证
	creds, err := credentials.NewClientTLSFromFile("../pkg/tls/server.pem", "go-grpc-example")
	if err != nil {
		log.Fatalf("Failed to create TLS credentials %v", err)
	}
	// 连接服务器
	conn, err := grpc.Dial(Address, grpc.WithTransportCredentials(creds))
	if err != nil {
		log.Fatalf("net.Connect err: %v", err)
	}
	defer conn.Close()

	// 建立gRPC连接
	grpcClient = pb.NewSimpleClient(conn)
}
  • credentials.NewClientTLSFromFile: Construct a TLS certificate for the client from the input certificate file.
  • grpc.WithTransportCredentials: Configure connection level security credentials (for example, TLS / SSL) and return a DialOption for connecting to the server.

Complete client.go code

At this point, TLS certificate authentication has been completed, and gRPC transmission is no longer a clear text transmission. In addition, adding custom authentication methods can make gRPC relatively more secure. The following uses Token authentication as an example to introduce how gRPC adds a custom verification method.

Token authentication

When the client sends a request, it adds Token to the context context.Context. When the server receives the request, it first obtains token verification from the context, and then passes the verification to the next step.

The client requests to add Token to the context

type PerRPCCredentials interface {
    GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error)
    RequireTransportSecurity() bool
}

Defined by default in gRPC PerRPCCredentials, it provides an interface for custom authentication. Its role is to add the required security authentication information to the context of each RPC method. It contains 2 methods:

  • GetRequestMetadata: Get the metadata required for the current authentication request
  • RequireTransportSecurity: Do you need secure transmission based on TLS authentication

Next we implement these two methods

// Token token认证
type Token struct {
	AppID     string
	AppSecret string
}

// GetRequestMetadata 获取当前请求认证所需的元数据(metadata)
func (t *Token) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
	return map[string]string{"app_id": t.AppID, "app_secret": t.AppSecret}, nil
}

// RequireTransportSecurity 是否需要基于 TLS 认证进行安全传输
func (t *Token) RequireTransportSecurity() bool {
	return true
}

Then add a custom verification method when calling Dial in the client

//构建Token
	token := auth.Token{
		AppID:     "grpc_token",
		AppSecret: "123456",
	}
	// 连接服务器
	conn, err := grpc.Dial(Address, grpc.WithTransportCredentials(creds), grpc.WithPerRPCCredentials(&token))

Complete client.go code

Server verification token

First need to get metadata from the context, and then parse the token from the metadata to verify

// Check 验证token
func Check(ctx context.Context) error {
	//从上下文中获取元数据
	md, ok := metadata.FromIncomingContext(ctx)
	if !ok {
		return status.Errorf(codes.Unauthenticated, "获取Token失败")
	}
	var (
		appID     string
		appSecret string
	)
	if value, ok := md["app_id"]; ok {
		appID = value[0]
	}
	if value, ok := md["app_secret"]; ok {
		appSecret = value[0]
	}
	if appID != "grpc_token" || appSecret != "123456" {
		return status.Errorf(codes.Unauthenticated, "Token无效: app_id=%s, app_secret=%s", appID, appSecret)
	}
	return nil
}
  • metadata.FromIncomingContext: Get metadata from the context

Complete server.go code

to sum up

This article introduces how to add TLS certificate authentication and custom authentication to gRPC to make gRPC more secure. However, in the above Token authentication code, when the server verifies the Token, it is necessary to add Token verification before each method, which is more troublesome. The next article will introduce how to use the gRPC interceptor to cancel this repeated step.

Tutorial source address: https://github.com/Bingjian-Zhu/go-grpc-example

reference:

Guess you like

Origin www.cnblogs.com/FireworksEasyCool/p/12710325.html