2022-04-01 13:38:58 -04:00
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
2023-02-02 17:15:17 -08:00
2021-10-19 17:21:41 -04:00
package controller
import (
"context"
2024-04-06 13:48:47 -07:00
"fmt"
2021-10-19 17:21:41 -04:00
"math"
"net"
2024-04-06 13:48:47 -07:00
"net/http"
"strings"
2021-10-19 17:21:41 -04:00
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
2021-12-16 15:13:28 -08:00
grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
2021-10-19 17:21:41 -04:00
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/hashicorp/boundary/globals"
2022-05-09 12:45:10 -07:00
"github.com/hashicorp/boundary/internal/daemon/controller/common"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers"
2021-10-19 17:21:41 -04:00
"github.com/hashicorp/boundary/internal/db"
"github.com/hashicorp/boundary/internal/errors"
2023-09-12 08:15:34 -04:00
"github.com/hashicorp/boundary/internal/event"
2021-10-19 17:21:41 -04:00
"github.com/hashicorp/boundary/internal/kms"
2022-04-01 13:38:58 -04:00
"github.com/hashicorp/boundary/internal/types/subtypes"
2024-04-06 13:48:47 -07:00
"github.com/hashicorp/go-uuid"
2021-10-19 17:21:41 -04:00
"google.golang.org/grpc"
2024-02-13 10:54:48 -05:00
"google.golang.org/grpc/credentials/insecure"
2024-04-06 13:48:47 -07:00
"google.golang.org/grpc/metadata"
2021-10-19 17:21:41 -04:00
"google.golang.org/grpc/test/bufconn"
)
const gatewayTarget = ""
2022-03-09 20:41:15 +00:00
type grpcServerListener interface {
2021-10-19 17:21:41 -04:00
net . Listener
Dial () ( net . Conn , error )
}
2022-03-09 20:41:15 +00:00
func gatewayDialOptions ( lis grpcServerListener ) [] grpc . DialOption {
2021-10-19 17:21:41 -04:00
return [] grpc . DialOption {
2024-02-13 10:54:48 -05:00
grpc . WithTransportCredentials ( insecure . NewCredentials ()),
2021-10-19 17:21:41 -04:00
grpc . WithContextDialer ( func ( context . Context , string ) ( net . Conn , error ) {
return lis . Dial ()
}),
2023-06-05 12:13:05 -04:00
grpc . WithDefaultCallOptions ( grpc . MaxCallRecvMsgSize ( math . MaxInt32 )),
grpc . WithDefaultCallOptions ( grpc . MaxCallSendMsgSize ( math . MaxInt32 )),
2021-10-19 17:21:41 -04:00
}
}
2023-02-13 11:56:53 -08:00
type noDelimiterStreamingMarshaler struct {
runtime . Marshaler
}
func ( noDelimiterStreamingMarshaler ) Delimiter () [] byte {
return nil
}
2022-03-09 20:41:15 +00:00
func newGrpcGatewayMux () * runtime . ServeMux {
2021-10-19 17:21:41 -04:00
return runtime . NewServeMux (
2024-04-06 13:48:47 -07:00
runtime . WithMetadata ( correlationIdAnnotator ),
2023-02-13 11:56:53 -08:00
runtime . WithMarshalerOption ( runtime . MIMEWildcard , & noDelimiterStreamingMarshaler {
& runtime . HTTPBodyMarshaler {
Marshaler : handlers . JSONMarshaler (),
},
2021-10-19 17:21:41 -04:00
}),
runtime . WithErrorHandler ( handlers . ErrorHandler ()),
runtime . WithForwardResponseOption ( handlers . OutgoingResponseFilter ),
2024-08-28 09:30:05 -04:00
runtime . WithDisablePathLengthFallback (),
2021-10-19 17:21:41 -04:00
)
}
2024-04-06 13:48:47 -07:00
func correlationIdAnnotator ( _ context . Context , req * http . Request ) metadata . MD {
var correlationId string
for k , v := range req . Header {
if strings . ToLower ( k ) == globals . CorrelationIdKey {
correlationId = v [ 0 ]
break
}
}
if correlationId == "" {
var err error
correlationId , err = uuid . GenerateUUID ()
// GenerateUUID should not return an error. If it does, panic since there is no
// err return path here.
if err != nil {
panic ( fmt . Sprintf ( "failed to generate correlation id: %v" , err ))
}
}
return metadata . New ( map [ string ] string {
globals . CorrelationIdKey : correlationId ,
})
}
2022-03-09 20:41:15 +00:00
// newGrpcServerListener will create an in-memory listener for the gRPC server.
func newGrpcServerListener () grpcServerListener {
buffer := globals . DefaultMaxRequestSize // seems like a reasonable size for the ring buffer, but then happily change the size if more info becomes available
return bufconn . Listen ( int ( buffer ))
}
func newGrpcServer (
2021-10-23 21:23:49 -04:00
ctx context . Context ,
iamRepoFn common . IamRepoFactory ,
authTokenRepoFn common . AuthTokenRepoFactory ,
serversRepoFn common . ServersRepoFactory ,
2022-10-27 09:01:05 -04:00
passwordAuthRepoFn common . PasswordAuthRepoFactory ,
oidcAuthRepoFn common . OidcAuthRepoFactory ,
2023-03-15 11:40:40 -04:00
ldapAuthRepoFn common . LdapAuthRepoFactory ,
2024-02-13 09:17:41 -08:00
aliasRepoFn common . AliasRepoFactory ,
2021-10-23 21:23:49 -04:00
kms * kms . Kms ,
eventer * event . Eventer ,
) ( * grpc . Server , string , error ) {
2022-03-09 20:41:15 +00:00
const op = "controller.newGrpcServer"
2023-06-06 17:09:08 -04:00
ticket , err := db . NewPrivateId ( ctx , "gwticket" )
2021-10-19 17:21:41 -04:00
if err != nil {
return nil , "" , errors . Wrap ( ctx , err , op , errors . WithMsg ( "unable to generate gateway ticket" ))
}
2023-05-20 05:45:39 -04:00
unaryCtxInterceptor , err := requestCtxUnaryInterceptor ( ctx , iamRepoFn , authTokenRepoFn , serversRepoFn , passwordAuthRepoFn , oidcAuthRepoFn , ldapAuthRepoFn , kms , ticket , eventer )
2023-05-20 07:23:10 -04:00
if err != nil {
return nil , "" , err
}
streamCtxInterceptor , err := requestCtxStreamInterceptor (
ctx ,
iamRepoFn ,
authTokenRepoFn ,
serversRepoFn ,
passwordAuthRepoFn ,
oidcAuthRepoFn ,
ldapAuthRepoFn ,
kms ,
ticket ,
eventer ,
)
2021-10-19 17:21:41 -04:00
if err != nil {
return nil , "" , err
}
return grpc . NewServer (
grpc . MaxRecvMsgSize ( math . MaxInt32 ),
grpc . MaxSendMsgSize ( math . MaxInt32 ),
2023-05-20 07:23:10 -04:00
grpc . StreamInterceptor (
grpc_middleware . ChainStreamServer (
streamCtxInterceptor ,
),
),
2021-10-23 21:23:49 -04:00
grpc . UnaryInterceptor (
grpc_middleware . ChainUnaryServer (
2023-05-20 05:45:39 -04:00
unaryCtxInterceptor , // populated requestInfo from headers into the request ctx
2024-04-06 13:48:47 -07:00
correlationIdInterceptor ( ctx ), // populate correlationId from headers or generate random id
2022-04-06 09:05:22 -04:00
errorInterceptor ( ctx ), // convert domain and api errors into headers for the http proxy
2024-02-13 09:17:41 -08:00
aliasResolutionInterceptor ( ctx , aliasRepoFn ), // Resolve ids when an alias is provided
2022-04-01 13:38:58 -04:00
subtypes . AttributeTransformerInterceptor ( ctx ), // convert to/from generic attributes from/to subtype specific attributes
2023-09-19 17:16:37 -07:00
eventsRequestInterceptor ( ctx ), // before we get started, send the required events with the request
2022-04-01 13:38:58 -04:00
statusCodeInterceptor ( ctx ), // convert grpc codes into http status codes for the http proxy (can modify the resp)
2023-09-19 17:16:37 -07:00
eventsResponseInterceptor ( ctx ), // as we finish, send the required events with the response
2021-12-16 15:13:28 -08:00
grpc_recovery . UnaryServerInterceptor ( // recover from panics with a grpc internal error
grpc_recovery . WithRecoveryHandlerContext ( recoveryHandler ()),
),
2021-10-23 21:23:49 -04:00
),
),
2021-10-19 17:21:41 -04:00
), ticket , nil
}