Compare commits

...

4 Commits

Author SHA1 Message Date
Nathan Verzemnieks 98398224dd Import libcap for sandbox privilege drop; fix semconv import 2026-01-14 12:44:31 +01:00
Nathan Verzemnieks 34d6243685 Specify temp dir so socket is created in the right place 2026-01-14 12:44:31 +01:00
Nathan Verzemnieks 10650ae196 Trying a different approach using a go-plugin RunnerFunc 2026-01-14 12:44:30 +01:00
Nathan Verzemnieks 6995872f68 Feat: experimental sandbox mode for community plugins 2026-01-14 12:44:30 +01:00
6 changed files with 50 additions and 15 deletions
+9 -4
View File
@@ -32,14 +32,14 @@ require (
github.com/armon/go-radix v1.0.0 // @grafana/grafana-app-platform-squad
github.com/aws/aws-sdk-go v1.55.7 // @grafana/aws-datasources
github.com/aws/aws-sdk-go-v2 v1.40.0 // @grafana/aws-datasources
github.com/aws/aws-sdk-go-v2/credentials v1.18.21 // indirect; @grafana/grafana-operator-experience-squad
github.com/aws/aws-sdk-go-v2/credentials v1.18.21 // @grafana/grafana-operator-experience-squad
github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.45.3 // @grafana/aws-datasources
github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.51.0 // @grafana/aws-datasources
github.com/aws/aws-sdk-go-v2/service/ec2 v1.225.2 // @grafana/aws-datasources
github.com/aws/aws-sdk-go-v2/service/oam v1.18.3 // @grafana/aws-datasources
github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.26.6 // @grafana/aws-datasources
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.40.1 // @grafana/grafana-operator-experience-squad
github.com/aws/aws-sdk-go-v2/service/sts v1.39.1 // indirect; @grafana/grafana-operator-experience-squad
github.com/aws/aws-sdk-go-v2/service/sts v1.39.1 // @grafana/grafana-operator-experience-squad
github.com/aws/smithy-go v1.23.2 // @grafana/aws-datasources
github.com/beevik/etree v1.4.1 // @grafana/grafana-backend-group
github.com/benbjohnson/clock v1.3.5 // @grafana/alerting-backend
@@ -120,7 +120,7 @@ require (
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // @grafana/identity-access-team
github.com/hashicorp/go-hclog v1.6.3 // @grafana/plugins-platform-backend
github.com/hashicorp/go-multierror v1.1.1 // @grafana/alerting-squad
github.com/hashicorp/go-plugin v1.7.0 // indirect; @grafana/plugins-platform-backend
github.com/hashicorp/go-plugin v1.7.0 // @grafana/plugins-platform-backend
github.com/hashicorp/go-version v1.7.0 // @grafana/grafana-backend-group
github.com/hashicorp/golang-lru/v2 v2.0.7 // @grafana/alerting-backend
github.com/hashicorp/hcl/v2 v2.24.0 // @grafana/alerting-backend
@@ -251,7 +251,6 @@ require (
github.com/grafana/grafana/apps/iam v0.0.0 // @grafana/identity-access-team
github.com/grafana/grafana/apps/logsdrilldown v0.0.0 // @grafana/observability-logs
github.com/grafana/grafana/apps/playlist v0.0.0 // @grafana/grafana-app-platform-squad
github.com/grafana/grafana/apps/plugins v0.0.0 // @grafana/plugins-platform-backend
github.com/grafana/grafana/apps/preferences v0.0.0 // @grafana/grafana-app-platform-squad
github.com/grafana/grafana/apps/provisioning v0.0.0 // @grafana/grafana-app-platform-squad
github.com/grafana/grafana/apps/quotas v0.0.0-20251209183543-1013d74f13f2 // @grafana/grafana-search-and-storage
@@ -656,6 +655,11 @@ require (
sigs.k8s.io/yaml v1.6.0 // indirect
)
require (
github.com/grafana/grafana/apps/plugins v0.0.0-00010101000000-000000000000
kernel.org/pub/linux/libs/security/libcap/cap v1.2.77
)
require (
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/IBM/pgxpoolprometheus v1.1.2 // indirect
@@ -698,6 +702,7 @@ require (
github.com/tklauser/go-sysconf v0.3.14 // indirect
github.com/tklauser/numcpus v0.8.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
kernel.org/pub/linux/libs/security/libcap/psx v1.2.77 // indirect
)
// Use fork of crewjam/saml with fixes for some issues until changes get merged into upstream
+4
View File
@@ -3706,6 +3706,10 @@ k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfX
k8s.io/utils v0.0.0-20190809000727-6c36bc71fc4a/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck=
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
kernel.org/pub/linux/libs/security/libcap/cap v1.2.77 h1:iQtQTjFUOcTT19fI8sTCzYXsjeVs56et3D8AbKS2Uks=
kernel.org/pub/linux/libs/security/libcap/cap v1.2.77/go.mod h1:oV+IO8kGh0B7TxErbydDe2+BRmi9g/W0CkpVV+QBTJU=
kernel.org/pub/linux/libs/security/libcap/psx v1.2.77 h1:Z06sMOzc0GNCwp6efaVrIrz4ywGJ1v+DP0pjVkOfDuA=
kernel.org/pub/linux/libs/security/libcap/psx v1.2.77/go.mod h1:+l6Ee2F59XiJ2I6WR5ObpC1utCQJZ/VLsEbQCD8RG24=
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
+4
View File
@@ -68,6 +68,10 @@ func MainApp() *cli.App {
if cmd != nil {
app.Commands = append(app.Commands, cmd)
}
sandbox := f.GetSandboxCommand()
if sandbox != nil {
app.Commands = append(app.Commands, sandbox)
}
}
return app
+23 -11
View File
@@ -1,10 +1,10 @@
package grpcplugin
import (
"os"
"os/exec"
"runtime"
"github.com/grafana/grafana-plugin-sdk-go/backend/grpcplugin"
"github.com/hashicorp/go-hclog"
goplugin "github.com/hashicorp/go-plugin"
"github.com/hashicorp/go-plugin/runner"
@@ -14,6 +14,7 @@ import (
"go.opentelemetry.io/otel/trace/embedded"
"google.golang.org/grpc"
"github.com/grafana/grafana-plugin-sdk-go/backend/grpcplugin"
"github.com/grafana/grafana/pkg/plugins/backendplugin"
"github.com/grafana/grafana/pkg/plugins/backendplugin/pluginextensionv2"
"github.com/grafana/grafana/pkg/plugins/log"
@@ -65,16 +66,7 @@ func newClientConfig(descriptor PluginDescriptor, env []string, logger log.Logge
if runtime.GOOS == "linux" && descriptor.containerMode.enabled {
return containerClientConfig(executablePath, descriptor.containerMode.image, descriptor.containerMode.tag, logger, versionedPlugins, skipHostEnvVars, tracer)
}
logger.Debug("Using process mode", "os", runtime.GOOS, "executablePath", executablePath)
// We can ignore gosec G201 here, since the dynamic part of executablePath comes from the plugin definition
// nolint:gosec
cmd := exec.Command(executablePath, descriptor.executableArgs...)
cmd.Env = env
return &goplugin.ClientConfig{
Cmd: cmd,
cfg := &goplugin.ClientConfig{
HandshakeConfig: handshake,
VersionedPlugins: versionedPlugins,
SkipHostEnv: skipHostEnvVars,
@@ -90,6 +82,25 @@ func newClientConfig(descriptor PluginDescriptor, env []string, logger log.Logge
grpc.WithStatsHandler(otelgrpc.NewClientHandler(otelgrpc.WithTracerProvider(newClientTracerProvider(tracer)))),
},
}
if descriptor.runnerFunc != nil {
cfg.RunnerFunc = descriptor.runnerFunc
td, err := os.MkdirTemp("", "plugin")
if err != nil {
// TODO: what do we do here?
td = "/tmp"
}
cfg.UnixSocketConfig = &goplugin.UnixSocketConfig{TempDir: td}
logger.Debug("Using runner mode", "os", runtime.GOOS, "executablePath", executablePath)
} else {
logger.Debug("Using process mode", "os", runtime.GOOS, "executablePath", executablePath)
// We can ignore gosec G201 here, since the dynamic part of executablePath comes from the plugin definition
// nolint:gosec
cfg.Cmd = exec.Command(executablePath, descriptor.executableArgs...)
cfg.Cmd.Env = env
}
return cfg
}
func containerClientConfig(executablePath, containerImage, containerTag string, logger log.Logger, versionedPlugins map[int]goplugin.PluginSet, skipHostEnvVars bool, tracer trace.Tracer) *goplugin.ClientConfig {
@@ -127,6 +138,7 @@ type PluginDescriptor struct {
skipHostEnvVars bool
managed bool
containerMode containerModeOpts
runnerFunc func(l hclog.Logger, cmd *exec.Cmd, tmpDir string) (runner.Runner, error)
versionedPlugins map[int]goplugin.PluginSet
startRendererFn StartRendererFunc
}
@@ -3,6 +3,9 @@ package grpcplugin
import (
"context"
"errors"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-plugin/runner"
"os/exec"
"go.opentelemetry.io/otel/trace"
"google.golang.org/grpc"
@@ -49,6 +52,7 @@ type ProtoClientOpts struct {
ExecutableArgs []string
Env []string
ContainerMode ContainerModeOpts
RunnerFunc func(l hclog.Logger, cmd *exec.Cmd, tmpDir string) (runner.Runner, error)
SkipHostEnvVars bool
Logger log.Logger
Tracer trace.Tracer
@@ -73,6 +77,7 @@ func NewProtoClient(opts ProtoClientOpts) (ProtoClient, error) {
image: opts.ContainerMode.Image,
tag: opts.ContainerMode.Tag,
},
runnerFunc: opts.RunnerFunc,
skipHostEnvVars: opts.SkipHostEnvVars,
},
opts.Logger,
@@ -14,6 +14,7 @@ type BuildInfo struct {
type APIServerFactory interface {
GetCLICommand(info BuildInfo) *cli.Command
GetSandboxCommand() *cli.Command
}
// NOOP
@@ -26,3 +27,7 @@ type NoOpAPIServerFactory struct{}
func (f *NoOpAPIServerFactory) GetCLICommand(info BuildInfo) *cli.Command {
return nil
}
func (f *NoOpAPIServerFactory) GetSandboxCommand() *cli.Command {
return nil
}