-
Notifications
You must be signed in to change notification settings - Fork 609
/
scopes.go
111 lines (96 loc) · 3 KB
/
scopes.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
110
111
package rbac
import (
"fmt"
"github.com/google/uuid"
"golang.org/x/xerrors"
)
// WorkspaceAgentScope returns a scope that is the same as ScopeAll but can only
// affect resources in the allow list. Only a scope is returned as the roles
// should come from the workspace owner.
func WorkspaceAgentScope(workspaceID, ownerID uuid.UUID) Scope {
allScope, err := ScopeAll.Expand()
if err != nil {
panic("failed to expand scope all, this should never happen")
}
return Scope{
// TODO: We want to limit the role too to be extra safe.
// Even though the allowlist blocks anything else, it is still good
// incase we change the behavior of the allowlist. The allowlist is new
// and evolving.
Role: allScope.Role,
// This prevents the agent from being able to access any other resource.
AllowIDList: []string{
workspaceID.String(),
ownerID.String(),
// TODO: Might want to include the template the workspace uses too?
},
}
}
const (
ScopeAll ScopeName = "all"
ScopeApplicationConnect ScopeName = "application_connect"
)
// TODO: Support passing in scopeID list for allowlisting resources.
var builtinScopes = map[ScopeName]Scope{
// ScopeAll is a special scope that allows access to all resources. During
// authorize checks it is usually not used directly and skips scope checks.
ScopeAll: {
Role: Role{
Name: fmt.Sprintf("Scope_%s", ScopeAll),
DisplayName: "All operations",
Site: Permissions(map[string][]Action{
ResourceWildcard.Type: {WildcardSymbol},
}),
Org: map[string][]Permission{},
User: []Permission{},
},
AllowIDList: []string{WildcardSymbol},
},
ScopeApplicationConnect: {
Role: Role{
Name: fmt.Sprintf("Scope_%s", ScopeApplicationConnect),
DisplayName: "Ability to connect to applications",
Site: Permissions(map[string][]Action{
ResourceWorkspaceApplicationConnect.Type: {ActionCreate},
}),
Org: map[string][]Permission{},
User: []Permission{},
},
AllowIDList: []string{WildcardSymbol},
},
}
type ExpandableScope interface {
Expand() (Scope, error)
// Name is for logging and tracing purposes, we want to know the human
// name of the scope.
Name() string
}
type ScopeName string
func (name ScopeName) Expand() (Scope, error) {
return ExpandScope(name)
}
func (name ScopeName) Name() string {
return string(name)
}
// Scope acts the exact same as a Role with the addition that is can also
// apply an AllowIDList. Any resource being checked against a Scope will
// reject any resource that is not in the AllowIDList.
// To not use an AllowIDList to reject authorization, use a wildcard for the
// AllowIDList. Eg: 'AllowIDList: []string{WildcardSymbol}'
type Scope struct {
Role
AllowIDList []string `json:"allow_list"`
}
func (s Scope) Expand() (Scope, error) {
return s, nil
}
func (s Scope) Name() string {
return s.Role.Name
}
func ExpandScope(scope ScopeName) (Scope, error) {
role, ok := builtinScopes[scope]
if !ok {
return Scope{}, xerrors.Errorf("no scope named %q", scope)
}
return role, nil
}