Add grpcserver test coverage
- Add comprehensive test file for internal/grpcserver package - Cover interceptors, system, engine, policy, and auth handlers - Cover pbToRule/ruleToPB conversion helpers - 37 tests total; CA/PKI/ACME and Login/Logout skipped (require live deps) Co-authored-by: Junie <junie@jetbrains.com>
This commit is contained in:
@@ -12,7 +12,7 @@ import (
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/metadata"
|
||||
|
||||
pb "git.wntrmute.dev/kyle/metacrypt/gen/metacrypt/v1"
|
||||
pb "git.wntrmute.dev/kyle/metacrypt/gen/metacrypt/v2"
|
||||
)
|
||||
|
||||
// VaultClient wraps the gRPC stubs for communicating with the vault.
|
||||
@@ -22,6 +22,7 @@ type VaultClient struct {
|
||||
auth pb.AuthServiceClient
|
||||
engine pb.EngineServiceClient
|
||||
pki pb.PKIServiceClient
|
||||
ca pb.CAServiceClient
|
||||
}
|
||||
|
||||
// NewVaultClient dials the vault gRPC server and returns a client.
|
||||
@@ -58,6 +59,7 @@ func NewVaultClient(addr, caCertPath string, logger *slog.Logger) (*VaultClient,
|
||||
auth: pb.NewAuthServiceClient(conn),
|
||||
engine: pb.NewEngineServiceClient(conn),
|
||||
pki: pb.NewPKIServiceClient(conn),
|
||||
ca: pb.NewCAServiceClient(conn),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -156,39 +158,16 @@ func (c *VaultClient) Mount(ctx context.Context, token, name, engineType string,
|
||||
Type: engineType,
|
||||
}
|
||||
if len(config) > 0 {
|
||||
s, err := structFromMap(config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("webserver: encode mount config: %w", err)
|
||||
cfg := make(map[string]string, len(config))
|
||||
for k, v := range config {
|
||||
cfg[k] = fmt.Sprintf("%v", v)
|
||||
}
|
||||
req.Config = s
|
||||
req.Config = cfg
|
||||
}
|
||||
_, err := c.engine.Mount(withToken(ctx, token), req)
|
||||
return err
|
||||
}
|
||||
|
||||
// EngineRequest sends a generic engine operation to the vault.
|
||||
func (c *VaultClient) EngineRequest(ctx context.Context, token, mount, operation string, data map[string]interface{}) (map[string]interface{}, error) {
|
||||
req := &pb.ExecuteRequest{
|
||||
Mount: mount,
|
||||
Operation: operation,
|
||||
}
|
||||
if len(data) > 0 {
|
||||
s, err := structFromMap(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("webserver: encode engine request: %w", err)
|
||||
}
|
||||
req.Data = s
|
||||
}
|
||||
resp, err := c.engine.Execute(withToken(ctx, token), req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Data == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return resp.Data.AsMap(), nil
|
||||
}
|
||||
|
||||
// GetRootCert returns the root CA certificate PEM for the given mount.
|
||||
func (c *VaultClient) GetRootCert(ctx context.Context, mount string) ([]byte, error) {
|
||||
resp, err := c.pki.GetRootCert(ctx, &pb.GetRootCertRequest{Mount: mount})
|
||||
@@ -206,3 +185,126 @@ func (c *VaultClient) GetIssuerCert(ctx context.Context, mount, issuer string) (
|
||||
}
|
||||
return resp.CertPem, nil
|
||||
}
|
||||
|
||||
// ImportRoot imports an existing root CA certificate and key into the given mount.
|
||||
func (c *VaultClient) ImportRoot(ctx context.Context, token, mount, certPEM, keyPEM string) error {
|
||||
_, err := c.ca.ImportRoot(withToken(ctx, token), &pb.ImportRootRequest{
|
||||
Mount: mount,
|
||||
CertPem: []byte(certPEM),
|
||||
KeyPem: []byte(keyPEM),
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// CreateIssuerRequest holds parameters for creating an intermediate CA issuer.
|
||||
type CreateIssuerRequest struct {
|
||||
Mount string
|
||||
Name string
|
||||
KeyAlgorithm string
|
||||
KeySize int32
|
||||
Expiry string
|
||||
MaxTTL string
|
||||
}
|
||||
|
||||
// CreateIssuer creates a new intermediate CA issuer on the given mount.
|
||||
func (c *VaultClient) CreateIssuer(ctx context.Context, token string, req CreateIssuerRequest) error {
|
||||
_, err := c.ca.CreateIssuer(withToken(ctx, token), &pb.CreateIssuerRequest{
|
||||
Mount: req.Mount,
|
||||
Name: req.Name,
|
||||
KeyAlgorithm: req.KeyAlgorithm,
|
||||
KeySize: req.KeySize,
|
||||
Expiry: req.Expiry,
|
||||
MaxTtl: req.MaxTTL,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// ListIssuers returns the names of all issuers for the given mount.
|
||||
func (c *VaultClient) ListIssuers(ctx context.Context, token, mount string) ([]string, error) {
|
||||
resp, err := c.ca.ListIssuers(withToken(ctx, token), &pb.ListIssuersRequest{Mount: mount})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.Issuers, nil
|
||||
}
|
||||
|
||||
// IssueCertRequest holds parameters for issuing a leaf certificate.
|
||||
type IssueCertRequest struct {
|
||||
Mount string
|
||||
Issuer string
|
||||
Profile string
|
||||
CommonName string
|
||||
DNSNames []string
|
||||
IPAddresses []string
|
||||
TTL string
|
||||
KeyUsages []string
|
||||
ExtKeyUsages []string
|
||||
}
|
||||
|
||||
// IssuedCert holds the result of a certificate issuance.
|
||||
type IssuedCert struct {
|
||||
Serial string
|
||||
CertPEM string
|
||||
KeyPEM string
|
||||
ChainPEM string
|
||||
ExpiresAt string
|
||||
}
|
||||
|
||||
// IssueCert issues a new leaf certificate from the named issuer.
|
||||
func (c *VaultClient) IssueCert(ctx context.Context, token string, req IssueCertRequest) (*IssuedCert, error) {
|
||||
resp, err := c.ca.IssueCert(withToken(ctx, token), &pb.IssueCertRequest{
|
||||
Mount: req.Mount,
|
||||
Issuer: req.Issuer,
|
||||
Profile: req.Profile,
|
||||
CommonName: req.CommonName,
|
||||
DnsNames: req.DNSNames,
|
||||
IpAddresses: req.IPAddresses,
|
||||
Ttl: req.TTL,
|
||||
KeyUsages: req.KeyUsages,
|
||||
ExtKeyUsages: req.ExtKeyUsages,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
issued := &IssuedCert{
|
||||
Serial: resp.Serial,
|
||||
CertPEM: string(resp.CertPem),
|
||||
KeyPEM: string(resp.KeyPem),
|
||||
ChainPEM: string(resp.ChainPem),
|
||||
}
|
||||
if resp.ExpiresAt != nil {
|
||||
issued.ExpiresAt = resp.ExpiresAt.AsTime().Format("2006-01-02T15:04:05Z")
|
||||
}
|
||||
return issued, nil
|
||||
}
|
||||
|
||||
// CertSummary holds lightweight certificate metadata for list views.
|
||||
type CertSummary struct {
|
||||
Serial string
|
||||
Issuer string
|
||||
CommonName string
|
||||
Profile string
|
||||
ExpiresAt string
|
||||
}
|
||||
|
||||
// ListCerts returns all certificate summaries for the given mount.
|
||||
func (c *VaultClient) ListCerts(ctx context.Context, token, mount string) ([]CertSummary, error) {
|
||||
resp, err := c.ca.ListCerts(withToken(ctx, token), &pb.ListCertsRequest{Mount: mount})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
certs := make([]CertSummary, 0, len(resp.Certs))
|
||||
for _, s := range resp.Certs {
|
||||
cs := CertSummary{
|
||||
Serial: s.Serial,
|
||||
Issuer: s.Issuer,
|
||||
CommonName: s.CommonName,
|
||||
Profile: s.Profile,
|
||||
}
|
||||
if s.ExpiresAt != nil {
|
||||
cs.ExpiresAt = s.ExpiresAt.AsTime().Format("2006-01-02T15:04:05Z")
|
||||
}
|
||||
certs = append(certs, cs)
|
||||
}
|
||||
return certs, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user