Skip to content

unsafesystems/cachaca

Repository files navigation

Cachaça

codecov Go Reference

Cachaça (Portuguese pronunciation: kaˈʃasɐ) is a distilled spirit made from fermented sugarcane juice. Also known as pinga, caninha, and other names, it is the most popular spirit among distilled alcoholic beverages in Brazil. Outside Brazil, cachaça is used almost exclusively as an ingredient in tropical drinks, with the caipirinha being the most famous cocktail. In Brazil, caipirinha is often paired with the dish feijoada. (Source: Wikipedia).

Cachaca is an opinionated gRPC/gRPC-web/REST/HTTP server. The server is intended to handle the heavy lifting of server configuration and handling authorization with a pluggable interface.

  • gRPC, gRPC-web, REST and HTTP are multiplexed onto a single port
  • Authorizer middleware supports modular support for a variety of authorization types
    • mTLS authorizer supports client certificate based authorization
    • OAuth/OIDC authorizer supports interoperability with an IdP
  • Consistent logging by forcing all logs through a single zerolog logger

While being opinionated in the implementation, the intention is to stay as consistent and close to standards and best practices as possible.

Under the hood

Because cachaca is intended to simplify implementation of gRPC/gRPC-web/REST services it is based on a variety of libraries:

Initializing the server

A minimal example to run the server works is provided. As can be seen, the server object can be used directly in order to register HTTP and gRPC endpoints.

Please note that gRPC-web is simply a proxy to gRPC so there is no additional setup necessary.

Example:

server, _ := NewServer()
l, _ := net.Listen("tcp", fmt.Sprintf(":%d", 0))

server.GET("/ping", func(context *gin.Context) {
    context.String(http.StatusOK, "pong")
})

if err := server.Serve(l); err != nil {
	panic(err)
}

Using an authorizer

The authorizers can register themselves with the server and shall be passed to the server on initialization. The provided example uses the OIDC authorizer implementation - but the other implementations work similar.

Example:

// Prepare the OAuth/OIDC authorizer
provider, _ := rp.NewRelyingPartyOIDC("issuer", "clientId", "clientSecret", "http://localhost:8443/oidc/authorize", []string{"openid"})
signingKey := &jose.SigningKey{Algorithm: jose.HS256, Key: []byte(uuid.NewString())}

authorizer := oidc.NewAuthorizer(signingKey)
authorizer.RegisterRelyingParty("test", provider)

server, _ := NewServer(authorizer)
l, _ := net.Listen("tcp", ":8443")

if err := server.Serve(l); err != nil {
	panic(err)
}

Accessing the credentials from the environment

auth/auth.go exposes the auth.GetCredentials function which allows access to the credentials from the authorizer middleware from the *gin.Context variable in HTTP requests and context.Context variable in gRPC requests.

Each authorizer middleware ships with its own Credentials object which must be used to retrieve the credentials.

Example:

func (s *Service) CommonName(ctx context.Context, _ *CommonNameRequest) (*CommonNameResponse, error) {
	commonName, ok := auth.GetCredentials[string](ctx)
	if !ok {
		return nil, status.Error(codes.Unauthenticated, "no credentials found")
	}

	return &CommonNameResponse{CommonName: *commonName}, nil
}

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published