Skip to content

Commit

Permalink
Feature: Optionally return secrets over gRPC instead of writing to di…
Browse files Browse the repository at this point in the history
…sk (#89)
  • Loading branch information
manedurphy authored Jun 1, 2021
1 parent ff21e5c commit a5dbd65
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 160 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ GOARCH?=amd64
GOLANG_IMAGE?=docker.mirror.hashicorp.services/golang:1.16.2
K8S_VERSION?=v1.20.2
CI_TEST_ARGS=
CSI_DRIVER_VERSION=0.0.20
CSI_DRIVER_VERSION=0.0.21
VAULT_HELM_VERSION=0.10.0
ifdef CI
override CI_TEST_ARGS:=--junitfile=$(TEST_RESULTS_DIR)/go-test/results.xml --jsonfile=$(TEST_RESULTS_DIR)/go-test/results.json
Expand Down
10 changes: 5 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ require (
github.com/stretchr/testify v1.6.1
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 // indirect
google.golang.org/grpc v1.29.1
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c
k8s.io/api v0.20.0
k8s.io/apimachinery v0.20.0
k8s.io/client-go v0.20.0
sigs.k8s.io/secrets-store-csi-driver v0.0.20
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
k8s.io/api v0.20.2
k8s.io/apimachinery v0.20.2
k8s.io/client-go v0.20.2
sigs.k8s.io/secrets-store-csi-driver v0.0.21
)
202 changes: 78 additions & 124 deletions go.sum

Large diffs are not rendered by default.

30 changes: 25 additions & 5 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
pb "sigs.k8s.io/secrets-store-csi-driver/provider/v1alpha1"
)

// provider implements the secrets-store-csi-driver provider interface
Expand Down Expand Up @@ -182,6 +183,10 @@ func (p *provider) getSecret(ctx context.Context, client *api.Client, secretConf
}
p.logger.Debug("Requesting secret", "secretConfig", secretConfig, "method", req.Method, "path", req.URL.Path, "params", req.Params)

if err != nil {
return "", fmt.Errorf("could not generate request: %v", err)
}

secret, err = vaultclient.Do(ctx, client, req)
if err != nil {
return "", fmt.Errorf("couldn't read secret %q: %w", secretConfig.ObjectName, err)
Expand Down Expand Up @@ -209,7 +214,7 @@ func (p *provider) getSecret(ctx context.Context, client *api.Client, secretConf
}

// MountSecretsStoreObjectContent mounts content of the vault object to target path
func (p *provider) MountSecretsStoreObjectContent(ctx context.Context, cfg config.Config) (map[string]string, error) {
func (p *provider) HandleMountRequest(ctx context.Context, cfg config.Config, writeSecrets bool) (*pb.MountResponse, error) {
versions := make(map[string]string)

client, err := vaultclient.New(cfg.Parameters.VaultAddress, cfg.Parameters.VaultTLSConfig)
Expand All @@ -229,19 +234,34 @@ func (p *provider) MountSecretsStoreObjectContent(ctx context.Context, cfg confi
return nil, err
}

var files []*pb.File
for _, secret := range cfg.Parameters.Secrets {
content, err := p.getSecret(ctx, client, secret)
if err != nil {
return nil, err
}
versions[fmt.Sprintf("%s:%s:%s", secret.ObjectName, secret.SecretPath, secret.Method)] = "0"
err = writeSecret(p.logger, cfg.TargetPath, secret.ObjectName, content, cfg.FilePermission)
if err != nil {
return nil, err

if writeSecrets {
err = writeSecret(p.logger, cfg.TargetPath, secret.ObjectName, content, cfg.FilePermission)
if err != nil {
return nil, err
}
} else {
files = append(files, &pb.File{Path: secret.ObjectName, Mode: int32(cfg.FilePermission), Contents: []byte(content)})
p.logger.Info("secret added to mount response", "directory", cfg.TargetPath, "file", secret.ObjectName)
}
}

return versions, nil
var ov []*pb.ObjectVersion
for k, v := range versions {
ov = append(ov, &pb.ObjectVersion{Id: k, Version: v})
}

return &pb.MountResponse{
ObjectVersion: ov,
Files: files,
}, nil
}

func writeSecret(logger hclog.Logger, directory string, file string, content string, permission os.FileMode) error {
Expand Down
23 changes: 5 additions & 18 deletions internal/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ var (

// Server implements the secrets-store-csi-driver provider gRPC service interface.
type Server struct {
Logger hclog.Logger
Logger hclog.Logger
WriteSecrets bool
}

func (p *Server) Version(context.Context, *pb.VersionRequest) (*pb.VersionResponse, error) {
Expand All @@ -29,30 +30,16 @@ func (p *Server) Version(context.Context, *pb.VersionRequest) (*pb.VersionRespon
}

func (p *Server) Mount(ctx context.Context, req *pb.MountRequest) (*pb.MountResponse, error) {
versions, err := p.handleMountRequest(ctx, req.Attributes, req.TargetPath, req.Permission)
if err != nil {
return nil, err
}

var ov []*pb.ObjectVersion
for k, v := range versions {
ov = append(ov, &pb.ObjectVersion{Id: k, Version: v})
}

return &pb.MountResponse{ObjectVersion: ov}, nil
}

func (p *Server) handleMountRequest(ctx context.Context, parametersStr, targetPath, permissionStr string) (map[string]string, error) {
cfg, err := config.Parse(p.Logger.Named("config"), parametersStr, targetPath, permissionStr)
cfg, err := config.Parse(p.Logger.Named("config"), req.Attributes, req.TargetPath, req.Permission)
if err != nil {
return nil, err
}

provider := provider.NewProvider(p.Logger.Named("provider"))
versions, err := provider.MountSecretsStoreObjectContent(ctx, cfg)
resp, err := provider.HandleMountRequest(ctx, cfg, p.WriteSecrets)
if err != nil {
return nil, fmt.Errorf("error making mount request: %w", err)
}

return versions, nil
return resp, nil
}
12 changes: 7 additions & 5 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ import (
)

var (
endpoint = flag.String("endpoint", "/tmp/vault.sock", "path to socket on which to listen for driver gRPC calls")
debug = flag.Bool("debug", false, "sets log to debug level")
healthAddr = flag.String("health_addr", ":8080", "configure http listener for reporting health")
selfVersion = flag.Bool("version", false, "prints the version information")
endpoint = flag.String("endpoint", "/tmp/vault.sock", "path to socket on which to listen for driver gRPC calls")
debug = flag.Bool("debug", false, "sets log to debug level")
healthAddr = flag.String("health_addr", ":8080", "configure http listener for reporting health")
selfVersion = flag.Bool("version", false, "prints the version information")
writeSecrets = flag.Bool("write_secrets", true, "write secrets directly to filesystem (true), or send secrets to CSI driver in gRPC response (false)")
)

func main() {
Expand Down Expand Up @@ -83,7 +84,8 @@ func realMain(logger hclog.Logger) error {
logger.Info(fmt.Sprintf("Listening on %s", *endpoint))

s := &providerserver.Server{
Logger: serverLogger,
Logger: serverLogger,
WriteSecrets: *writeSecrets,
}
pb.RegisterCSIDriverProviderServer(server, s)

Expand Down
7 changes: 5 additions & 2 deletions test/bats/provider.bats
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ teardown(){
@test "2 Sync with kubernetes secrets" {
# Deploy some pods that should cause k8s secrets to be created.
kubectl --namespace=test apply -f $CONFIGS/nginx-kv-env-var.yaml

# This line sometimes throws an error
kubectl --namespace=test wait --for=condition=Ready --timeout=5m pod -l app=nginx

POD=$(kubectl --namespace=test get pod -l app=nginx -o jsonpath="{.items[0].metadata.name}")
Expand Down Expand Up @@ -174,12 +176,13 @@ teardown(){
# There isn't really an event we can wait for to ensure this has happened.
for i in {0..60}; do
result="$(kubectl --namespace=test get secret kvsecret -o json | jq '.metadata.ownerReferences | length')"
if [[ "$result" -eq 2 ]]; then
if [[ "$result" -eq 1 ]]; then
break
fi
sleep 1
done
[[ "$result" -eq 2 ]]
# The secret's owner is the ReplicaSet created by the deployment from $CONFIGS/nginx-kv-env-var.yaml
[[ "$result" -eq 1 ]]

# Wait for secret deletion in a background process.
kubectl --namespace=test wait --for=delete --timeout=60s secret kvsecret &
Expand Down

0 comments on commit a5dbd65

Please sign in to comment.