forked from Velocidex/velociraptor
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsecrets.go
109 lines (82 loc) · 3.88 KB
/
secrets.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package services
/*
This service manages secrets to be used inside the VQL environment.
Many VQL plugins and functions require a secret to perform their
role. For example, the SSH accessor requires ssh credentials to log
into the remote system. The upload_s3() function requires S3
credentials to upload files to the cloud.
Traditionally credentials were provided directly to these VQL
functions via VQL parameters or VQL environment variables. This
works and it is the most direct way but it makes it difficult to
protect these secrets from malicious use and to prevent them from
leaking unintentionally.
For example, consider an artifact that uploads data to Elastic. That
artifact needs API credentials to push to elastic and these need to
be provided in the GUI as an artifact parameter. This means that:
1. The user managing the server needs to now have access to Elastic credentials.
2. If we are not careful, anyone viewing the artifact in the GUI can
just read the credentials as parameters (It is possible to set
parameter types to redacted to ensure the GUI redacts these
parameters).
## Dedicated secret managements
The secrets service solves this issue by managing secrets outside of
VQL. Once a secret is registered with the secrets service by name,
the user is unable to retrieve the secret from VQL
directly. Instead, the VQL plugins that require that secret can ask
for it in code providing the identity of the principal under which
the query is run.
If the principal is allowed to use the secret the service will
return the service for use by the plugin.
Now there is no risk of any secrets leaking in the VQL
environment. For example, the following query:
SELECT upload_s3(secret="MyS3Credentials", path=OSPath) FROM scope()
Will retrieve the `MyS3Credentials` if the calling user is allowed
and the file will be uploaded to s3, but there is no possibility any
more of retrieving the plain text secret from VQL.
Equally, if another user copies the artifact, they can not
automatically use the secret, unless they too have access to it.
This allows more careful management of secrets and reduces
opportunity for credential leaks.
*/
import (
"context"
"github.com/Velocidex/ordereddict"
api_proto "www.velocidex.com/golang/velociraptor/api/proto"
config_proto "www.velocidex.com/golang/velociraptor/config/proto"
"www.velocidex.com/golang/vfilter"
)
type Secret struct {
*api_proto.Secret
Data *ordereddict.Dict
}
type SecretsService interface {
// Allows the user to define a new type of secret and attach a VQL
// lambda to allow verification of new secrets.
DefineSecret(ctx context.Context, definition *api_proto.SecretDefinition) error
DeleteSecretDefinition(
ctx context.Context, definition *api_proto.SecretDefinition) error
GetSecretDefinitions(ctx context.Context) []*api_proto.SecretDefinition
// Add a new managed secret. This function applies any verifiers
// to ensure the secret is valid.
AddSecret(ctx context.Context, scope vfilter.Scope,
type_name, secret_name string,
secret *ordereddict.Dict) error
// Grants access to the secret to the specified users.
ModifySecret(ctx context.Context,
request *api_proto.ModifySecretRequest) error
// Retrieve a secret. This function may only be called internally
// from VQL plugins/functions. The secrets may not be leaked into
// the VQL environment. The function checks the principal against
// the secret's ACLs to ensure they are allowed access to it.
GetSecret(ctx context.Context,
principal, type_name, secret_name string) (*Secret, error)
GetSecretMetadata(ctx context.Context,
type_name, secret_name string) (*Secret, error)
}
func GetSecretsService(config_obj *config_proto.Config) (SecretsService, error) {
org_manager, err := GetOrgManager()
if err != nil {
return nil, err
}
return org_manager.Services(config_obj.OrgId).SecretsService()
}