github.com/hashicorp/vault/sdk@v0.13.0/database/dbplugin/grpc_transport.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package dbplugin 5 6 import ( 7 "context" 8 "encoding/json" 9 "errors" 10 "time" 11 12 "github.com/golang/protobuf/ptypes" 13 "github.com/hashicorp/vault/sdk/helper/pluginutil" 14 "google.golang.org/grpc" 15 "google.golang.org/grpc/codes" 16 "google.golang.org/grpc/status" 17 ) 18 19 var ( 20 ErrPluginShutdown = errors.New("plugin shutdown") 21 ErrPluginStaticUnsupported = errors.New("database plugin does not support Static Accounts") 22 ) 23 24 // ---- gRPC Server domain ---- 25 26 type gRPCServer struct { 27 UnimplementedDatabaseServer 28 29 impl Database 30 } 31 32 func (s *gRPCServer) Type(context.Context, *Empty) (*TypeResponse, error) { 33 t, err := s.impl.Type() 34 if err != nil { 35 return nil, err 36 } 37 38 return &TypeResponse{ 39 Type: t, 40 }, nil 41 } 42 43 func (s *gRPCServer) CreateUser(ctx context.Context, req *CreateUserRequest) (*CreateUserResponse, error) { 44 e, err := ptypes.Timestamp(req.Expiration) 45 if err != nil { 46 return nil, err 47 } 48 49 u, p, err := s.impl.CreateUser(ctx, *req.Statements, *req.UsernameConfig, e) 50 51 return &CreateUserResponse{ 52 Username: u, 53 Password: p, 54 }, err 55 } 56 57 func (s *gRPCServer) RenewUser(ctx context.Context, req *RenewUserRequest) (*Empty, error) { 58 e, err := ptypes.Timestamp(req.Expiration) 59 if err != nil { 60 return nil, err 61 } 62 err = s.impl.RenewUser(ctx, *req.Statements, req.Username, e) 63 return &Empty{}, err 64 } 65 66 func (s *gRPCServer) RevokeUser(ctx context.Context, req *RevokeUserRequest) (*Empty, error) { 67 err := s.impl.RevokeUser(ctx, *req.Statements, req.Username) 68 return &Empty{}, err 69 } 70 71 func (s *gRPCServer) RotateRootCredentials(ctx context.Context, req *RotateRootCredentialsRequest) (*RotateRootCredentialsResponse, error) { 72 resp, err := s.impl.RotateRootCredentials(ctx, req.Statements) 73 if err != nil { 74 return nil, err 75 } 76 77 respConfig, err := json.Marshal(resp) 78 if err != nil { 79 return nil, err 80 } 81 82 return &RotateRootCredentialsResponse{ 83 Config: respConfig, 84 }, err 85 } 86 87 func (s *gRPCServer) Initialize(ctx context.Context, req *InitializeRequest) (*Empty, error) { 88 _, err := s.Init(ctx, &InitRequest{ 89 Config: req.Config, 90 VerifyConnection: req.VerifyConnection, 91 }) 92 return &Empty{}, err 93 } 94 95 func (s *gRPCServer) Init(ctx context.Context, req *InitRequest) (*InitResponse, error) { 96 config := map[string]interface{}{} 97 err := json.Unmarshal(req.Config, &config) 98 if err != nil { 99 return nil, err 100 } 101 102 resp, err := s.impl.Init(ctx, config, req.VerifyConnection) 103 if err != nil { 104 return nil, err 105 } 106 107 respConfig, err := json.Marshal(resp) 108 if err != nil { 109 return nil, err 110 } 111 112 return &InitResponse{ 113 Config: respConfig, 114 }, err 115 } 116 117 func (s *gRPCServer) Close(_ context.Context, _ *Empty) (*Empty, error) { 118 s.impl.Close() 119 return &Empty{}, nil 120 } 121 122 func (s *gRPCServer) GenerateCredentials(ctx context.Context, _ *Empty) (*GenerateCredentialsResponse, error) { 123 p, err := s.impl.GenerateCredentials(ctx) 124 if err != nil { 125 return nil, err 126 } 127 128 return &GenerateCredentialsResponse{ 129 Password: p, 130 }, nil 131 } 132 133 func (s *gRPCServer) SetCredentials(ctx context.Context, req *SetCredentialsRequest) (*SetCredentialsResponse, error) { 134 username, password, err := s.impl.SetCredentials(ctx, *req.Statements, *req.StaticUserConfig) 135 if err != nil { 136 return nil, err 137 } 138 139 return &SetCredentialsResponse{ 140 Username: username, 141 Password: password, 142 }, err 143 } 144 145 // ---- gRPC client domain ---- 146 147 type gRPCClient struct { 148 client DatabaseClient 149 clientConn *grpc.ClientConn 150 151 doneCtx context.Context 152 } 153 154 func (c *gRPCClient) Type() (string, error) { 155 resp, err := c.client.Type(c.doneCtx, &Empty{}) 156 if err != nil { 157 return "", err 158 } 159 160 return resp.Type, err 161 } 162 163 func (c *gRPCClient) CreateUser(ctx context.Context, statements Statements, usernameConfig UsernameConfig, expiration time.Time) (username string, password string, err error) { 164 t, err := ptypes.TimestampProto(expiration) 165 if err != nil { 166 return "", "", err 167 } 168 169 ctx, cancel := context.WithCancel(ctx) 170 quitCh := pluginutil.CtxCancelIfCanceled(cancel, c.doneCtx) 171 defer close(quitCh) 172 defer cancel() 173 174 resp, err := c.client.CreateUser(ctx, &CreateUserRequest{ 175 Statements: &statements, 176 UsernameConfig: &usernameConfig, 177 Expiration: t, 178 }) 179 if err != nil { 180 if c.doneCtx.Err() != nil { 181 return "", "", ErrPluginShutdown 182 } 183 184 return "", "", err 185 } 186 187 return resp.Username, resp.Password, err 188 } 189 190 func (c *gRPCClient) RenewUser(ctx context.Context, statements Statements, username string, expiration time.Time) error { 191 t, err := ptypes.TimestampProto(expiration) 192 if err != nil { 193 return err 194 } 195 196 ctx, cancel := context.WithCancel(ctx) 197 quitCh := pluginutil.CtxCancelIfCanceled(cancel, c.doneCtx) 198 defer close(quitCh) 199 defer cancel() 200 201 _, err = c.client.RenewUser(ctx, &RenewUserRequest{ 202 Statements: &statements, 203 Username: username, 204 Expiration: t, 205 }) 206 if err != nil { 207 if c.doneCtx.Err() != nil { 208 return ErrPluginShutdown 209 } 210 211 return err 212 } 213 214 return nil 215 } 216 217 func (c *gRPCClient) RevokeUser(ctx context.Context, statements Statements, username string) error { 218 ctx, cancel := context.WithCancel(ctx) 219 quitCh := pluginutil.CtxCancelIfCanceled(cancel, c.doneCtx) 220 defer close(quitCh) 221 defer cancel() 222 223 _, err := c.client.RevokeUser(ctx, &RevokeUserRequest{ 224 Statements: &statements, 225 Username: username, 226 }) 227 if err != nil { 228 if c.doneCtx.Err() != nil { 229 return ErrPluginShutdown 230 } 231 232 return err 233 } 234 235 return nil 236 } 237 238 func (c *gRPCClient) RotateRootCredentials(ctx context.Context, statements []string) (conf map[string]interface{}, err error) { 239 ctx, cancel := context.WithCancel(ctx) 240 quitCh := pluginutil.CtxCancelIfCanceled(cancel, c.doneCtx) 241 defer close(quitCh) 242 defer cancel() 243 244 resp, err := c.client.RotateRootCredentials(ctx, &RotateRootCredentialsRequest{ 245 Statements: statements, 246 }) 247 if err != nil { 248 if c.doneCtx.Err() != nil { 249 return nil, ErrPluginShutdown 250 } 251 252 return nil, err 253 } 254 255 if err := json.Unmarshal(resp.Config, &conf); err != nil { 256 return nil, err 257 } 258 259 return conf, nil 260 } 261 262 func (c *gRPCClient) Initialize(ctx context.Context, conf map[string]interface{}, verifyConnection bool) error { 263 _, err := c.Init(ctx, conf, verifyConnection) 264 return err 265 } 266 267 func (c *gRPCClient) Init(ctx context.Context, conf map[string]interface{}, verifyConnection bool) (map[string]interface{}, error) { 268 configRaw, err := json.Marshal(conf) 269 if err != nil { 270 return nil, err 271 } 272 273 ctx, cancel := context.WithCancel(ctx) 274 quitCh := pluginutil.CtxCancelIfCanceled(cancel, c.doneCtx) 275 defer close(quitCh) 276 defer cancel() 277 278 resp, err := c.client.Init(ctx, &InitRequest{ 279 Config: configRaw, 280 VerifyConnection: verifyConnection, 281 }) 282 if err != nil { 283 // Fall back to old call if not implemented 284 grpcStatus, ok := status.FromError(err) 285 if ok && grpcStatus.Code() == codes.Unimplemented { 286 _, err = c.client.Initialize(ctx, &InitializeRequest{ 287 Config: configRaw, 288 VerifyConnection: verifyConnection, 289 }) 290 if err == nil { 291 return conf, nil 292 } 293 } 294 295 if c.doneCtx.Err() != nil { 296 return nil, ErrPluginShutdown 297 } 298 return nil, err 299 } 300 301 if err := json.Unmarshal(resp.Config, &conf); err != nil { 302 return nil, err 303 } 304 return conf, nil 305 } 306 307 func (c *gRPCClient) Close() error { 308 _, err := c.client.Close(c.doneCtx, &Empty{}) 309 return err 310 } 311 312 func (c *gRPCClient) GenerateCredentials(ctx context.Context) (string, error) { 313 ctx, cancel := context.WithCancel(ctx) 314 quitCh := pluginutil.CtxCancelIfCanceled(cancel, c.doneCtx) 315 defer close(quitCh) 316 defer cancel() 317 318 resp, err := c.client.GenerateCredentials(ctx, &Empty{}) 319 if err != nil { 320 grpcStatus, ok := status.FromError(err) 321 if ok && grpcStatus.Code() == codes.Unimplemented { 322 return "", ErrPluginStaticUnsupported 323 } 324 325 if c.doneCtx.Err() != nil { 326 return "", ErrPluginShutdown 327 } 328 return "", err 329 } 330 331 return resp.Password, nil 332 } 333 334 func (c *gRPCClient) SetCredentials(ctx context.Context, statements Statements, staticUser StaticUserConfig) (username, password string, err error) { 335 ctx, cancel := context.WithCancel(ctx) 336 quitCh := pluginutil.CtxCancelIfCanceled(cancel, c.doneCtx) 337 defer close(quitCh) 338 defer cancel() 339 340 resp, err := c.client.SetCredentials(ctx, &SetCredentialsRequest{ 341 StaticUserConfig: &staticUser, 342 Statements: &statements, 343 }) 344 if err != nil { 345 // Fall back to old call if not implemented 346 grpcStatus, ok := status.FromError(err) 347 if ok && grpcStatus.Code() == codes.Unimplemented { 348 return "", "", ErrPluginStaticUnsupported 349 } 350 351 if c.doneCtx.Err() != nil { 352 return "", "", ErrPluginShutdown 353 } 354 return "", "", err 355 } 356 357 return resp.Username, resp.Password, err 358 }