Skip to content

Commit

Permalink
Added orgs() plugin and user management (Velocidex#1949)
Browse files Browse the repository at this point in the history
It is not possible in VQL to add users to different orgs and grant
them different access.

Also allow the query() plugin to runas a user and run within a
different org context. This allows scheduling of collection hunts
across different orgs as well retrieving the results from different
orgs.
  • Loading branch information
scudette authored Jul 21, 2022
1 parent 0afc25c commit 63e99f4
Show file tree
Hide file tree
Showing 92 changed files with 1,389 additions and 373 deletions.
38 changes: 0 additions & 38 deletions accessors/acl.go
Original file line number Diff line number Diff line change
@@ -1,39 +1 @@
package accessors

import (
"www.velocidex.com/golang/velociraptor/acls"
acl_proto "www.velocidex.com/golang/velociraptor/acls/proto"
config_proto "www.velocidex.com/golang/velociraptor/config/proto"
vql_subsystem "www.velocidex.com/golang/velociraptor/vql"
)

// Get a new, more restricted ACL manager suitable for remapping
// configuration. NOTE that this remapping manager can not give
// **more** permissions than before, but can only remove permissions
// from the existing token. It is useful when we want to block
// certaain plugins from working because we are emulating a more
// restricted environment. For example when analyzing a dead image on
// Windows we need to prevent wmi() plugin from interrogating the
// analysis host, therefore would typically remove the MACHINE_STATE
// permission.
func GetRemappingACLManager(
existing_manager vql_subsystem.ACLManager,
remap_config []*config_proto.RemappingConfig) (vql_subsystem.ACLManager, error) {
token := &acl_proto.ApiClientACL{}
for _, item := range remap_config {
if item.Type == "permissions" {
for _, perm := range item.Permissions {
allowed, err := existing_manager.CheckAccess(
acls.GetPermission(perm))
if err == nil && allowed {
err := acls.SetTokenPermission(token, perm)
if err != nil {
return nil, err
}
}
}
}
}

return &vql_subsystem.ServerACLManager{Token: token}, nil
}
3 changes: 2 additions & 1 deletion accessors/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"www.velocidex.com/golang/velociraptor/constants"
"www.velocidex.com/golang/velociraptor/json"
vql_subsystem "www.velocidex.com/golang/velociraptor/vql"
"www.velocidex.com/golang/velociraptor/vql/acl_managers"

_ "www.velocidex.com/golang/velociraptor/accessors/ntfs"
_ "www.velocidex.com/golang/velociraptor/accessors/offset"
Expand Down Expand Up @@ -128,7 +129,7 @@ var human_string_tests = []human_string_tests_t{

func TestOSPathHumanString(t *testing.T) {
scope := vql_subsystem.MakeScope().AppendVars(ordereddict.NewDict().
Set(vql_subsystem.ACL_MANAGER_VAR, vql_subsystem.NullACLManager{}).
Set(vql_subsystem.ACL_MANAGER_VAR, acl_managers.NullACLManager{}).
Set(constants.SCOPE_DEVICE_MANAGER,
accessors.GlobalDeviceManager.Copy()))

Expand Down
5 changes: 3 additions & 2 deletions accessors/file/accessor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"www.velocidex.com/golang/velociraptor/config"
"www.velocidex.com/golang/velociraptor/glob"
vql_subsystem "www.velocidex.com/golang/velociraptor/vql"
"www.velocidex.com/golang/velociraptor/vql/acl_managers"

_ "www.velocidex.com/golang/velociraptor/accessors/ntfs"
)
Expand Down Expand Up @@ -47,7 +48,7 @@ func (self *AccessorWindowsTestSuite) TestACL() {

// Try again with more premissions.
scope = vql_subsystem.MakeScope().AppendVars(ordereddict.NewDict().
Set(vql_subsystem.ACL_MANAGER_VAR, vql_subsystem.NullACLManager{}))
Set(vql_subsystem.ACL_MANAGER_VAR, acl_managers.NullACLManager{}))
scope.SetLogger(log.New(os.Stderr, " ", 0))

accessor, err = accessors.GetAccessor("file", scope)
Expand Down Expand Up @@ -90,7 +91,7 @@ func (self *AccessorWindowsTestSuite) TestSymlinks() {
assert.NoError(self.T(), err)

scope := vql_subsystem.MakeScope().AppendVars(ordereddict.NewDict().
Set(vql_subsystem.ACL_MANAGER_VAR, vql_subsystem.NullACLManager{}))
Set(vql_subsystem.ACL_MANAGER_VAR, acl_managers.NullACLManager{}))
scope.SetLogger(log.New(os.Stderr, " ", 0))
accessor, err := accessors.GetAccessor("file", scope)
assert.NoError(self.T(), err)
Expand Down
3 changes: 2 additions & 1 deletion accessors/ntfs/mft_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ import (
"github.com/Velocidex/ordereddict"
"www.velocidex.com/golang/velociraptor/accessors"
vql_subsystem "www.velocidex.com/golang/velociraptor/vql"
"www.velocidex.com/golang/velociraptor/vql/acl_managers"
"www.velocidex.com/golang/velociraptor/vtesting/assert"
)

func TestMFTFilesystemAccessor(t *testing.T) {
scope := vql_subsystem.MakeScope().AppendVars(ordereddict.NewDict().
Set(vql_subsystem.ACL_MANAGER_VAR, vql_subsystem.NullACLManager{}))
Set(vql_subsystem.ACL_MANAGER_VAR, acl_managers.NullACLManager{}))
scope.SetLogger(log.New(os.Stderr, " ", 0))

abs_path, _ := filepath.Abs("../../artifacts/testdata/files/test.ntfs.dd")
Expand Down
5 changes: 3 additions & 2 deletions accessors/ntfs/ntfs_accessor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"www.velocidex.com/golang/velociraptor/glob"
"www.velocidex.com/golang/velociraptor/json"
vql_subsystem "www.velocidex.com/golang/velociraptor/vql"
"www.velocidex.com/golang/velociraptor/vql/acl_managers"
"www.velocidex.com/golang/velociraptor/vtesting/assert"

_ "www.velocidex.com/golang/velociraptor/accessors/file"
Expand All @@ -23,7 +24,7 @@ import (
func TestNTFSFilesystemAccessor(t *testing.T) {
config_obj := config.GetDefaultConfig()
scope := vql_subsystem.MakeScope().AppendVars(ordereddict.NewDict().
Set(vql_subsystem.ACL_MANAGER_VAR, vql_subsystem.NullACLManager{}))
Set(vql_subsystem.ACL_MANAGER_VAR, acl_managers.NullACLManager{}))
scope.SetLogger(log.New(os.Stderr, " ", 0))

abs_path, _ := filepath.Abs("../../artifacts/testdata/files/test.ntfs.dd")
Expand Down Expand Up @@ -77,7 +78,7 @@ func TestNTFSFilesystemAccessorRemapping(t *testing.T) {
accessors.MustNewWindowsOSPath(""), root_fs_accessor)

scope := vql_subsystem.MakeScope().AppendVars(ordereddict.NewDict().
Set(vql_subsystem.ACL_MANAGER_VAR, vql_subsystem.NullACLManager{}))
Set(vql_subsystem.ACL_MANAGER_VAR, acl_managers.NullACLManager{}))
scope.SetLogger(log.New(os.Stderr, " ", 0))

abs_path, _ := filepath.Abs("../../artifacts/testdata/files/test.ntfs.dd")
Expand Down
3 changes: 2 additions & 1 deletion accessors/raw_registry/raw_registry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"www.velocidex.com/golang/velociraptor/json"
"www.velocidex.com/golang/velociraptor/logging"
vql_subsystem "www.velocidex.com/golang/velociraptor/vql"
"www.velocidex.com/golang/velociraptor/vql/acl_managers"
"www.velocidex.com/golang/vfilter"

_ "www.velocidex.com/golang/velociraptor/accessors/file"
Expand Down Expand Up @@ -69,7 +70,7 @@ func TestAccessorRawReg(t *testing.T) {

// Now repeat with proper access
scope = vql_subsystem.MakeScope().AppendVars(ordereddict.NewDict().
Set(vql_subsystem.ACL_MANAGER_VAR, vql_subsystem.NullACLManager{}))
Set(vql_subsystem.ACL_MANAGER_VAR, acl_managers.NullACLManager{}))

hits, err := runtest(scope)
assert.NoError(t, err)
Expand Down
5 changes: 3 additions & 2 deletions accessors/zip/gzip_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/Velocidex/ordereddict"
"www.velocidex.com/golang/velociraptor/accessors"
vql_subsystem "www.velocidex.com/golang/velociraptor/vql"
"www.velocidex.com/golang/velociraptor/vql/acl_managers"
"www.velocidex.com/golang/velociraptor/vtesting/assert"

_ "www.velocidex.com/golang/velociraptor/accessors/file"
Expand All @@ -18,7 +19,7 @@ import (

func TestAccessorGzip(t *testing.T) {
scope := vql_subsystem.MakeScope().AppendVars(ordereddict.NewDict().
Set(vql_subsystem.ACL_MANAGER_VAR, vql_subsystem.NullACLManager{}))
Set(vql_subsystem.ACL_MANAGER_VAR, acl_managers.NullACLManager{}))
scope.SetLogger(log.New(os.Stderr, " ", 0))

gzip_accessor, err := accessors.GetAccessor("gzip", scope)
Expand All @@ -37,7 +38,7 @@ func TestAccessorGzip(t *testing.T) {

func TestAccessorBzip2(t *testing.T) {
scope := vql_subsystem.MakeScope().AppendVars(ordereddict.NewDict().
Set(vql_subsystem.ACL_MANAGER_VAR, vql_subsystem.NullACLManager{}))
Set(vql_subsystem.ACL_MANAGER_VAR, acl_managers.NullACLManager{}))
scope.SetLogger(log.New(os.Stderr, " ", 0))

gzip_accessor, err := accessors.GetAccessor("bzip2", scope)
Expand Down
20 changes: 20 additions & 0 deletions acls/acls.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ const (
// Allowed to manage server configuration.
SERVER_ADMIN

// Allowed to manage orgs
ORG_ADMIN

// Allows the user to specify a different username for the query() plugin
IMPERSONATION

// Allowed to read arbitrary files from the filesystem.
FILESYSTEM_READ

Expand Down Expand Up @@ -147,6 +153,10 @@ func (self ACL_PERMISSION) String() string {
return "NOTEBOOK_EDITOR"
case SERVER_ADMIN:
return "SERVER_ADMIN"
case ORG_ADMIN:
return "ORG_ADMIN"
case IMPERSONATION:
return "IMPERSONATION"
case FILESYSTEM_READ:
return "FILESYSTEM_READ"
case FILESYSTEM_WRITE:
Expand Down Expand Up @@ -191,6 +201,10 @@ func GetPermission(name string) ACL_PERMISSION {
return NOTEBOOK_EDITOR
case "SERVER_ADMIN":
return SERVER_ADMIN
case "ORG_ADMIN":
return ORG_ADMIN
case "IMPERSONATION":
return IMPERSONATION
case "FILESYSTEM_READ":
return FILESYSTEM_READ
case "FILESYSTEM_WRITE":
Expand Down Expand Up @@ -356,6 +370,12 @@ func (self ACLManager) CheckAccessWithToken(
case SERVER_ADMIN:
return token.ServerAdmin, nil

case ORG_ADMIN:
return token.OrgAdmin, nil

case IMPERSONATION:
return token.Impersonation, nil

case FILESYSTEM_READ:
return token.FilesystemRead, nil

Expand Down
89 changes: 56 additions & 33 deletions acls/proto/acl.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions acls/proto/acl.proto
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ message ApiClientACL {
bool server_artifact_writer = 15;
bool execve = 7;
bool notebook_editor = 8;

// Has the ability to add/remove/list orgs. A user with
// server_admin on the root org will also receive org_admin.
bool org_admin = 19;

// Allows a user to run queries as another user.
bool impersonation = 20;

bool server_admin = 12;
bool filesystem_read = 13;
bool filesystem_write = 14;
Expand Down
16 changes: 15 additions & 1 deletion acls/roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (

func ValidateRole(role string) bool {
switch role {
case "administrator", "reader", "analyst", "investigator", "artifact_writer", "api":
case "org_admin", "administrator", "reader", "analyst", "investigator", "artifact_writer", "api":
return true
}

Expand Down Expand Up @@ -43,6 +43,10 @@ func SetTokenPermission(
token.NotebookEditor = true
case "SERVER_ADMIN":
token.ServerAdmin = true
case "ORG_ADMIN":
token.OrgAdmin = true
case "IMPERSONATION":
token.Impersonation = true
case "FILESYSTEM_READ":
token.FilesystemRead = true
case "FILESYSTEM_WRITE":
Expand All @@ -69,11 +73,15 @@ func GetRolePermissions(
for _, role := range roles {
switch role {

case "org_admin":
result.OrgAdmin = true

// Admins get all query access
case "administrator":
result.AllQuery = true
result.AnyQuery = true
result.ReadResults = true
result.Impersonation = true
result.LabelClients = true
result.CollectClient = true
result.CollectServer = true
Expand All @@ -87,6 +95,12 @@ func GetRolePermissions(
result.MachineState = true
result.PrepareResults = true

// An administrator for the root org is allowed to
// manipulate orgs.
if config_obj != nil && config_obj.OrgId == "" {
result.OrgAdmin = true
}

// Readers can view results but not edit or
// modify anything.
case "reader":
Expand Down
Loading

0 comments on commit 63e99f4

Please sign in to comment.