privilegedhelper

package
v0.0.28 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 11, 2026 License: Apache-2.0 Imports: 30 Imported by: 0

Documentation

Overview

Package privilegedhelper defines the authenticated wire protocol shared by rshell's privileged helper and the Datadog Private Action Runner.

Index

Constants

View Source
const (
	ProtocolVersion = 1
	MaxMessageBytes = 1 << 20
)
View Source
const (
	EscalationAllowed = "EscalationAllowed"
)

Variables

View Source
var File_privilegedhelper_private_action_proto protoreflect.FileDescriptor

Functions

This section is empty.

Types

type AgentPolicy added in v0.0.28

type AgentPolicy struct {
	AllowedCommands       []string            `json:"allowedCommands"`
	AllowedPaths          []string            `json:"allowedPaths"`
	AllowedSystemServices map[string][]string `json:"allowedSystemServices"`
	ElevatableCommands    []string            `json:"elevatableCommands"`
}

AgentPolicy is an unsigned, Agent-supplied authorization narrowing sent alongside the signed task envelope. It represents the Private Action Runner's local datadog.yaml restricted_shell.allowed_* operator settings, the same operator settings that already narrow the non-privileged rshell path. Because it is unsigned and supplied by a process the helper does not fully trust, it can only narrow (intersect with) the signed backend policy and any local root-owned policy.json — it can never grant a permission beyond what those already allow.

A nil ExecuteRequest.AgentPolicy means the Agent imposes no narrowing at this layer at all: the effective policy is exactly signed task ∩ optional policy.json, identical to the protocol's behavior before this field existed.

A non-nil AgentPolicy applies independently per field, mirroring the exact nil-vs-empty convention Credential (policy.json) and the Agent's own datadog.yaml operator settings already use elsewhere in this system: for each of AllowedCommands, AllowedPaths, AllowedSystemServices, and ElevatableCommands, a nil value means that axis is left unrestricted by this layer (defer entirely to signed ∩ policy.json for that axis), while a non-nil-but-empty value is an explicit kill switch that denies every grant on that axis regardless of what the signed task or policy.json allow. This lets an operator narrow only the axes they have configured — e.g. setting only AllowedCommands — without accidentally denying every system service or path just because those fields were left unset.

These fields intentionally omit `omitempty`: Go's encoding/json treats nil and empty slices/maps identically when omitempty is set, which would erase the nil-vs-empty distinction this type depends on once it crosses the wire.

type Client

type Client struct {
	SocketPath string
	Timeout    time.Duration
}

func (Client) Execute

func (c Client) Execute(ctx context.Context, req ExecuteRequest) (*ExecuteResponse, error)

func (Client) ExecuteSignedTask

func (c Client) ExecuteSignedTask(ctx context.Context, envelope SignedEnvelope) (*ExecuteResponse, error)

ExecuteSignedTask dispatches an original backend-signed task to the helper. It is the preferred client entry point because callers cannot accidentally select a protocol version or place authorization data outside the signature.

type ConnectionInfo

type ConnectionInfo struct {
	RunnerId string `protobuf:"bytes,4,opt,name=runner_id,json=runnerId,proto3" json:"runner_id,omitempty"`
	// contains filtered or unexported fields
}

func (*ConnectionInfo) Descriptor deprecated

func (*ConnectionInfo) Descriptor() ([]byte, []int)

Deprecated: Use ConnectionInfo.ProtoReflect.Descriptor instead.

func (*ConnectionInfo) GetRunnerId

func (x *ConnectionInfo) GetRunnerId() string

func (*ConnectionInfo) ProtoMessage

func (*ConnectionInfo) ProtoMessage()

func (*ConnectionInfo) ProtoReflect

func (x *ConnectionInfo) ProtoReflect() protoreflect.Message

func (*ConnectionInfo) Reset

func (x *ConnectionInfo) Reset()

func (*ConnectionInfo) String

func (x *ConnectionInfo) String() string

type Credential

type Credential struct {
	Version               int                 `json:"version"`
	OrgID                 int64               `json:"orgId"`
	RunnerID              string              `json:"runnerId"`
	Keys                  []CredentialKey     `json:"keys"`
	AllowedCommands       []string            `json:"allowedCommands"`
	AllowedPaths          []string            `json:"allowedPaths"`
	AllowedSystemServices map[string][]string `json:"allowedSystemServices"`
	ElevatableCommands    []string            `json:"elevatableCommands"`
	DirectorRoot          json.RawMessage     `json:"directorRoot,omitempty"`
	// contains filtered or unexported fields
}

func LoadCredential

func LoadCredential(path string) (*Credential, error)

func NewRequestCredential

func NewRequestCredential(keys []CredentialKey) (*Credential, error)

NewRequestCredential trusts one bare verification key supplied with the request and applies no local policy. The embedding application is responsible for independently gating this mode through administrator configuration.

func (*Credential) Verify

func (c *Credential) Verify(req ExecuteRequest, now time.Time) (*VerifiedCommand, error)

type CredentialKey

type CredentialKey struct {
	ID   string  `json:"id"`
	Type KeyType `json:"type"`
	PEM  string  `json:"pem"`
}

type DirectorKeyProof

type DirectorKeyProof struct {
	Roots      [][]byte `json:"roots,omitempty"`
	Targets    []byte   `json:"targets"`
	TargetPath string   `json:"targetPath"`
	TargetFile []byte   `json:"targetFile"`
}

DirectorKeyProof contains the TUF metadata needed to authenticate one AP_RUNNER_KEYS target from the Director root in the helper credential.

type ExecuteRequest

type ExecuteRequest struct {
	Version          int             `json:"version"`
	Envelope         SignedEnvelope  `json:"envelope"`
	VerificationKeys []CredentialKey `json:"verificationKeys,omitempty"`
	AgentPolicy      *AgentPolicy    `json:"agentPolicy,omitempty"`
}

func NewExecuteRequest

func NewExecuteRequest(envelope SignedEnvelope) ExecuteRequest

NewExecuteRequest wraps an original backend-signed task for transport to the privileged helper. Security-relevant task fields, including the command and its requested effective permissions, deliberately remain inside envelope.Data so that the helper can authenticate them before use.

type ExecuteResponse

type ExecuteResponse struct {
	Version         int      `json:"version"`
	ExitCode        int      `json:"exitCode"`
	Stdout          string   `json:"stdout,omitempty"`
	Stderr          string   `json:"stderr,omitempty"`
	SandboxWarnings []string `json:"sandboxWarnings,omitempty"`
	Error           string   `json:"error,omitempty"`
}

type ExecutionMode

type ExecutionMode string

ExecutionMode is derived exclusively from the authenticated action name and carried to the one-shot worker as part of the verified command policy.

const (
	ExecutionModeReadOnly    ExecutionMode = "readonly"
	ExecutionModeRemediation ExecutionMode = "remediation"
)

type Executor

type Executor interface {
	Execute(context.Context, *VerifiedCommand) (*ExecuteResponse, error)
}

type KeyType

type KeyType string
const (
	KeyTypeX509RSA KeyType = "X509_RSA"
	KeyTypeED25519 KeyType = "ED25519"
	// KeyTypeTUFDirector identifies a request-scoped Director proof transported
	// in CredentialKey.PEM for protocol-v1 compatibility. It is never decoded as
	// a bare verification key.
	KeyTypeTUFDirector KeyType = "TUF_DIRECTOR"
)

type PrivateActionTask

type PrivateActionTask struct {
	ActionName     string                 `protobuf:"bytes,1,opt,name=action_name,json=actionName,proto3" json:"action_name,omitempty"`
	BundleId       string                 `protobuf:"bytes,2,opt,name=bundle_id,json=bundleId,proto3" json:"bundle_id,omitempty"`
	OrgId          int64                  `protobuf:"varint,3,opt,name=org_id,json=orgId,proto3" json:"org_id,omitempty"`
	TaskId         string                 `protobuf:"bytes,4,opt,name=task_id,json=taskId,proto3" json:"task_id,omitempty"`
	Inputs         *structpb.Struct       `protobuf:"bytes,6,opt,name=inputs,proto3" json:"inputs,omitempty"`
	ConnectionInfo *ConnectionInfo        `protobuf:"bytes,10,opt,name=connection_info,json=connectionInfo,proto3" json:"connection_info,omitempty"`
	ExpirationTime *timestamppb.Timestamp `protobuf:"bytes,11,opt,name=expiration_time,json=expirationTime,proto3" json:"expiration_time,omitempty"`
	SystemInputs   *SystemInputs          `protobuf:"bytes,13,opt,name=system_inputs,json=systemInputs,proto3" json:"system_inputs,omitempty"`
	// contains filtered or unexported fields
}

PrivateActionTask is the security-relevant subset of the PAR task wire format. Field numbers intentionally match private_actions.proto in the datadog-agent repository. Unknown fields remain covered by the backend signature and are ignored when decoding.

func (*PrivateActionTask) Descriptor deprecated

func (*PrivateActionTask) Descriptor() ([]byte, []int)

Deprecated: Use PrivateActionTask.ProtoReflect.Descriptor instead.

func (*PrivateActionTask) GetActionName

func (x *PrivateActionTask) GetActionName() string

func (*PrivateActionTask) GetBundleId

func (x *PrivateActionTask) GetBundleId() string

func (*PrivateActionTask) GetConnectionInfo

func (x *PrivateActionTask) GetConnectionInfo() *ConnectionInfo

func (*PrivateActionTask) GetExpirationTime

func (x *PrivateActionTask) GetExpirationTime() *timestamppb.Timestamp

func (*PrivateActionTask) GetInputs

func (x *PrivateActionTask) GetInputs() *structpb.Struct

func (*PrivateActionTask) GetOrgId

func (x *PrivateActionTask) GetOrgId() int64

func (*PrivateActionTask) GetSystemInputs

func (x *PrivateActionTask) GetSystemInputs() *SystemInputs

func (*PrivateActionTask) GetTaskId

func (x *PrivateActionTask) GetTaskId() string

func (*PrivateActionTask) ProtoMessage

func (*PrivateActionTask) ProtoMessage()

func (*PrivateActionTask) ProtoReflect

func (x *PrivateActionTask) ProtoReflect() protoreflect.Message

func (*PrivateActionTask) Reset

func (x *PrivateActionTask) Reset()

func (*PrivateActionTask) String

func (x *PrivateActionTask) String() string

type RemoteAction

type RemoteAction struct {
	AllowedCommands []string                       `protobuf:"bytes,1,rep,name=allowed_commands,json=allowedCommands,proto3" json:"allowed_commands,omitempty"`
	AllowedPaths    []string                       `protobuf:"bytes,2,rep,name=allowed_paths,json=allowedPaths,proto3" json:"allowed_paths,omitempty"`
	SystemServices  map[string]*structpb.ListValue `` /* 177-byte string literal not displayed */
	// contains filtered or unexported fields
}

func (*RemoteAction) Descriptor deprecated

func (*RemoteAction) Descriptor() ([]byte, []int)

Deprecated: Use RemoteAction.ProtoReflect.Descriptor instead.

func (*RemoteAction) GetAllowedCommands

func (x *RemoteAction) GetAllowedCommands() []string

func (*RemoteAction) GetAllowedPaths

func (x *RemoteAction) GetAllowedPaths() []string

func (*RemoteAction) GetSystemServices added in v0.0.27

func (x *RemoteAction) GetSystemServices() map[string]*structpb.ListValue

func (*RemoteAction) ProtoMessage

func (*RemoteAction) ProtoMessage()

func (*RemoteAction) ProtoReflect

func (x *RemoteAction) ProtoReflect() protoreflect.Message

func (*RemoteAction) Reset

func (x *RemoteAction) Reset()

func (*RemoteAction) String

func (x *RemoteAction) String() string

type Server

type Server struct {
	Credential  *Credential
	Executor    Executor
	Now         func() time.Time
	IdleTimeout time.Duration
	LogWriter   io.Writer
}

func (*Server) Serve

func (s *Server) Serve(ctx context.Context, listener net.Listener) error

type Signature

type Signature struct {
	KeyType   KeyType `json:"keyType"`
	KeyID     string  `json:"keyId"`
	Signature []byte  `json:"signature"`
}

type SignedEnvelope

type SignedEnvelope struct {
	Data       []byte      `json:"data"`
	HashType   string      `json:"hashType"`
	Signatures []Signature `json:"signatures"`
}

SignedEnvelope contains the original backend-signed protobuf bytes. Trust roots are deliberately absent from the signed object. Helpers configured with a local Director root authenticate the request-scoped task key using its Director proof. Helpers without one trust the accompanying bare verification key; without a local policy, they use the signed backend policy unchanged.

type SystemInputs

type SystemInputs struct {

	// Types that are valid to be assigned to Input:
	//
	//	*SystemInputs_RemoteAction
	Input isSystemInputs_Input `protobuf_oneof:"input"`
	// contains filtered or unexported fields
}

func (*SystemInputs) Descriptor deprecated

func (*SystemInputs) Descriptor() ([]byte, []int)

Deprecated: Use SystemInputs.ProtoReflect.Descriptor instead.

func (*SystemInputs) GetInput

func (x *SystemInputs) GetInput() isSystemInputs_Input

func (*SystemInputs) GetRemoteAction

func (x *SystemInputs) GetRemoteAction() *RemoteAction

func (*SystemInputs) ProtoMessage

func (*SystemInputs) ProtoMessage()

func (*SystemInputs) ProtoReflect

func (x *SystemInputs) ProtoReflect() protoreflect.Message

func (*SystemInputs) Reset

func (x *SystemInputs) Reset()

func (*SystemInputs) String

func (x *SystemInputs) String() string

type SystemInputs_RemoteAction

type SystemInputs_RemoteAction struct {
	RemoteAction *RemoteAction `protobuf:"bytes,1,opt,name=remote_action,json=remoteAction,proto3,oneof"`
}

type VerifiedCommand

type VerifiedCommand struct {
	TaskID                string
	Command               string
	Mode                  ExecutionMode
	AllowedCommands       []string
	AllowedPaths          []string
	AllowedSystemServices map[string][]string
	ElevatableCommands    []string
	// contains filtered or unexported fields
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL