mirror of https://github.com/grafana/grafana.git
Unistore: Wire up inline secure values (#110072)
* Unistore: Wire up inline secure values * add validation and test * linter
This commit is contained in:
parent
e7ccefcf92
commit
1091054c25
|
|
@ -19,37 +19,46 @@ func ProvideInlineSecureValueService(
|
|||
accessClient authlib.AccessClient,
|
||||
) (contracts.InlineSecureValueSupport, error) {
|
||||
if cfg.SecretsManagement.GrpcClientEnable {
|
||||
grpcClientConfig := grpcutils.ReadGrpcClientConfig(cfg)
|
||||
|
||||
if cfg.SecretsManagement.GrpcServerAddress == "" {
|
||||
return nil, fmt.Errorf("grpc_server_address is required when grpc client is enabled")
|
||||
}
|
||||
|
||||
if grpcClientConfig.Token == "" || grpcClientConfig.TokenExchangeURL == "" {
|
||||
return nil, fmt.Errorf("grpc_client_authentication.token and grpc_client_authentication.token_exchange_url are required when grpc client is enabled")
|
||||
}
|
||||
|
||||
tokenExchangeClient, err := authnlib.NewTokenExchangeClient(authnlib.TokenExchangeConfig{
|
||||
Token: grpcClientConfig.Token,
|
||||
TokenExchangeURL: grpcClientConfig.TokenExchangeURL,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create token exchange client: %w", err)
|
||||
}
|
||||
|
||||
tlsConfig := readTLSFromConfig(cfg)
|
||||
|
||||
client, err := NewGRPCInlineClient(tokenExchangeClient, tracer, cfg.SecretsManagement.GrpcServerAddress, tlsConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create grpc inline secure value client: %w", err)
|
||||
}
|
||||
|
||||
return client, nil
|
||||
return NewGRPCSecureValueService(
|
||||
grpcutils.ReadGrpcClientConfig(cfg),
|
||||
cfg.SecretsManagement.GrpcServerAddress,
|
||||
readTLSFromConfig(cfg),
|
||||
tracer,
|
||||
)
|
||||
}
|
||||
|
||||
return NewLocalInlineSecureValueService(tracer, secureValueService, accessClient), nil
|
||||
}
|
||||
|
||||
func NewGRPCSecureValueService(tokenCfg *grpcutils.GrpcClientConfig,
|
||||
address string,
|
||||
tlsCfg TLSConfig,
|
||||
tracer trace.Tracer,
|
||||
) (contracts.InlineSecureValueSupport, error) {
|
||||
if address == "" {
|
||||
return nil, fmt.Errorf("grpc_server_address is required when grpc client is enabled")
|
||||
}
|
||||
|
||||
if tokenCfg.Token == "" || tokenCfg.TokenExchangeURL == "" {
|
||||
return nil, fmt.Errorf("grpc_client_authentication.token and grpc_client_authentication.token_exchange_url are required when grpc client is enabled")
|
||||
}
|
||||
|
||||
tokenExchangeClient, err := authnlib.NewTokenExchangeClient(authnlib.TokenExchangeConfig{
|
||||
Token: tokenCfg.Token,
|
||||
TokenExchangeURL: tokenCfg.TokenExchangeURL,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create token exchange client: %w", err)
|
||||
}
|
||||
|
||||
client, err := NewGRPCInlineClient(tokenExchangeClient, tracer, address, tlsCfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create grpc inline secure value client: %w", err)
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func readTLSFromConfig(cfg *setting.Cfg) TLSConfig {
|
||||
if !cfg.SecretsManagement.GrpcServerUseTLS {
|
||||
return TLSConfig{
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ import (
|
|||
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
secret "github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
|
||||
inlinesecurevalue "github.com/grafana/grafana/pkg/registry/apis/secret/inline"
|
||||
"github.com/grafana/grafana/pkg/services/authn/grpcutils"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/apistore"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resource"
|
||||
|
|
@ -51,6 +53,14 @@ type StorageOptions struct {
|
|||
GrpcClientAuthenticationTokenNamespace string
|
||||
GrpcClientAuthenticationAllowInsecure bool
|
||||
|
||||
// Secrets Manager Configuration for InlineSecureValueSupport
|
||||
SecretsManagerGrpcClientEnable bool
|
||||
SecretsManagerGrpcServerAddress string
|
||||
SecretsManagerGrpcServerUseTLS bool
|
||||
SecretsManagerGrpcServerTLSSkipVerify bool
|
||||
SecretsManagerGrpcServerTLSServerName string
|
||||
SecretsManagerGrpcServerTLSCAFile string
|
||||
|
||||
// For file storage, this is the requested path
|
||||
DataPath string
|
||||
|
||||
|
|
@ -92,6 +102,14 @@ func (o *StorageOptions) AddFlags(fs *pflag.FlagSet) {
|
|||
fs.StringVar(&o.GrpcClientAuthenticationTokenExchangeURL, "grpc-client-authentication-token-exchange-url", o.GrpcClientAuthenticationTokenExchangeURL, "Token exchange url for grpc client authentication")
|
||||
fs.StringVar(&o.GrpcClientAuthenticationTokenNamespace, "grpc-client-authentication-token-namespace", o.GrpcClientAuthenticationTokenNamespace, "Token namespace for grpc client authentication")
|
||||
fs.BoolVar(&o.GrpcClientAuthenticationAllowInsecure, "grpc-client-authentication-allow-insecure", o.GrpcClientAuthenticationAllowInsecure, "Allow insecure grpc client authentication")
|
||||
|
||||
// Secrets Manager Configuration flags
|
||||
fs.BoolVar(&o.SecretsManagerGrpcClientEnable, "grafana.secrets-manager.grpc-client-enable", false, "Enable gRPC client for secrets manager")
|
||||
fs.StringVar(&o.SecretsManagerGrpcServerAddress, "grafana.secrets-manager.grpc-server-address", "", "gRPC server address for secrets manager")
|
||||
fs.BoolVar(&o.SecretsManagerGrpcServerUseTLS, "grafana.secrets-manager.grpc-server-use-tls", false, "Use TLS for gRPC server communication")
|
||||
fs.BoolVar(&o.SecretsManagerGrpcServerTLSSkipVerify, "grafana.secrets-manager.grpc-server-tls-skip-verify", false, "Skip TLS verification for gRPC server")
|
||||
fs.StringVar(&o.SecretsManagerGrpcServerTLSServerName, "grafana.secrets-manager.grpc-server-tls-server-name", "", "Server name for TLS verification")
|
||||
fs.StringVar(&o.SecretsManagerGrpcServerTLSCAFile, "grafana.secrets-manager.grpc-server-tls-ca-file", "", "CA file for TLS verification")
|
||||
}
|
||||
|
||||
func (o *StorageOptions) Validate() []error {
|
||||
|
|
@ -130,10 +148,19 @@ func (o *StorageOptions) Validate() []error {
|
|||
errs = append(errs, fmt.Errorf("grpc client auth namespace is required for unified-grpc storage"))
|
||||
}
|
||||
}
|
||||
|
||||
if o.SecretsManagerGrpcClientEnable {
|
||||
if o.SecretsManagerGrpcServerAddress == "" {
|
||||
errs = append(errs, fmt.Errorf("secrets manager grpc server address is required for secrets manager grpc client"))
|
||||
}
|
||||
if o.SecretsManagerGrpcServerUseTLS && !o.SecretsManagerGrpcServerTLSSkipVerify && o.SecretsManagerGrpcServerTLSCAFile == "" {
|
||||
errs = append(errs, fmt.Errorf("secrets manager grpc server ca file is required for secrets manager grpc client"))
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
func (o *StorageOptions) ApplyTo(serverConfig *genericapiserver.RecommendedConfig, etcdOptions *options.EtcdOptions, tracer tracing.Tracer) error {
|
||||
func (o *StorageOptions) ApplyTo(serverConfig *genericapiserver.RecommendedConfig, etcdOptions *options.EtcdOptions, tracer tracing.Tracer, secureServing *options.SecureServingOptions) error {
|
||||
if o.StorageType != StorageTypeUnifiedGrpc {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -168,6 +195,35 @@ func (o *StorageOptions) ApplyTo(serverConfig *genericapiserver.RecommendedConfi
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// setup inline secrets if configured
|
||||
if o.InlineSecrets == nil && o.SecretsManagerGrpcClientEnable {
|
||||
tlsCfg := inlinesecurevalue.TLSConfig{
|
||||
UseTLS: o.SecretsManagerGrpcServerUseTLS,
|
||||
CAFile: o.SecretsManagerGrpcServerTLSCAFile,
|
||||
ServerName: o.SecretsManagerGrpcServerTLSServerName,
|
||||
InsecureSkipVerify: o.SecretsManagerGrpcServerTLSSkipVerify,
|
||||
}
|
||||
if o.SecretsManagerGrpcServerUseTLS && secureServing != nil {
|
||||
tlsCfg.CertFile = secureServing.ServerCert.CertKey.CertFile
|
||||
tlsCfg.KeyFile = secureServing.ServerCert.CertKey.KeyFile
|
||||
}
|
||||
inlineSecureValueService, err := inlinesecurevalue.NewGRPCSecureValueService(
|
||||
&grpcutils.GrpcClientConfig{
|
||||
Token: o.GrpcClientAuthenticationToken,
|
||||
TokenExchangeURL: o.GrpcClientAuthenticationTokenExchangeURL,
|
||||
TokenNamespace: o.GrpcClientAuthenticationTokenNamespace,
|
||||
},
|
||||
o.SecretsManagerGrpcServerAddress,
|
||||
tlsCfg,
|
||||
tracer,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create inline secure value service: %w", err)
|
||||
}
|
||||
o.InlineSecrets = inlineSecureValueService
|
||||
}
|
||||
|
||||
getter := apistore.NewRESTOptionsGetterForClient(unified, o.InlineSecrets, etcdOptions.StorageConfig, o.ConfigProvider)
|
||||
serverConfig.RESTOptionsGetter = getter
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -30,6 +30,47 @@ func TestStorageOptions_Validate(t *testing.T) {
|
|||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "with secrets manager grpc client and no server address",
|
||||
Opts: StorageOptions{
|
||||
StorageType: StorageTypeUnifiedGrpc,
|
||||
Address: "localhost:10000",
|
||||
GrpcClientAuthenticationToken: "1234",
|
||||
GrpcClientAuthenticationTokenExchangeURL: "http://localhost:8080",
|
||||
GrpcClientAuthenticationTokenNamespace: "*",
|
||||
SecretsManagerGrpcClientEnable: true,
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "with secrets manager grpc client and no server ca file",
|
||||
Opts: StorageOptions{
|
||||
StorageType: StorageTypeUnifiedGrpc,
|
||||
Address: "localhost:10000",
|
||||
GrpcClientAuthenticationToken: "1234",
|
||||
GrpcClientAuthenticationTokenExchangeURL: "http://localhost:8080",
|
||||
GrpcClientAuthenticationTokenNamespace: "*",
|
||||
SecretsManagerGrpcClientEnable: true,
|
||||
SecretsManagerGrpcServerAddress: "localhost:10000",
|
||||
SecretsManagerGrpcServerUseTLS: true,
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "with secrets manager grpc client and server ca file",
|
||||
Opts: StorageOptions{
|
||||
StorageType: StorageTypeUnifiedGrpc,
|
||||
Address: "localhost:10000",
|
||||
GrpcClientAuthenticationToken: "1234",
|
||||
GrpcClientAuthenticationTokenExchangeURL: "http://localhost:8080",
|
||||
GrpcClientAuthenticationTokenNamespace: "*",
|
||||
SecretsManagerGrpcClientEnable: true,
|
||||
SecretsManagerGrpcServerAddress: "localhost:10000",
|
||||
SecretsManagerGrpcServerUseTLS: true,
|
||||
SecretsManagerGrpcServerTLSCAFile: "ca.crt",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package sql
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
|
|
@ -13,6 +14,7 @@ import (
|
|||
"github.com/grafana/dskit/services"
|
||||
infraDB "github.com/grafana/grafana/pkg/infra/db"
|
||||
secrets "github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
|
||||
inlinesecurevalue "github.com/grafana/grafana/pkg/registry/apis/secret/inline"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
|
|
@ -48,6 +50,20 @@ func NewResourceServer(
|
|||
opts ServerOptions,
|
||||
) (resource.ResourceServer, error) {
|
||||
apiserverCfg := opts.Cfg.SectionWithEnvOverrides("grafana-apiserver")
|
||||
|
||||
if opts.SecureValues == nil && opts.Cfg != nil && opts.Cfg.SecretsManagement.GrpcClientEnable {
|
||||
inlineSecureValueService, err := inlinesecurevalue.ProvideInlineSecureValueService(
|
||||
opts.Cfg,
|
||||
opts.Tracer,
|
||||
nil, // not needed for gRPC client mode
|
||||
nil, // not needed for gRPC client mode
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create inline secure value service: %w", err)
|
||||
}
|
||||
opts.SecureValues = inlineSecureValueService
|
||||
}
|
||||
|
||||
serverOptions := resource.ResourceServerOptions{
|
||||
Tracer: opts.Tracer,
|
||||
Blob: resource.BlobConfig{
|
||||
|
|
|
|||
Loading…
Reference in New Issue