-
Notifications
You must be signed in to change notification settings - Fork 4.3k
/
Copy pathbackend.go
185 lines (158 loc) · 5.49 KB
/
backend.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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package approle
import (
"context"
"sync"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/consts"
"github.com/hashicorp/vault/sdk/helper/locksutil"
"github.com/hashicorp/vault/sdk/helper/salt"
"github.com/hashicorp/vault/sdk/logical"
)
const (
operationPrefixAppRole = "app-role"
secretIDPrefix = "secret_id/"
secretIDLocalPrefix = "secret_id_local/"
secretIDAccessorPrefix = "accessor/"
secretIDAccessorLocalPrefix = "accessor_local/"
)
// ReportedVersion is used to report a specific version to Vault.
var ReportedVersion = ""
type backend struct {
*framework.Backend
// The salt value to be used by the information to be accessed only
// by this backend.
salt *salt.Salt
saltMutex sync.RWMutex
// The view to use when creating the salt
view logical.Storage
// Guard to clean-up the expired SecretID entries
tidySecretIDCASGuard *uint32
// Locks to make changes to role entries. These will be initialized to a
// predefined number of locks when the backend is created, and will be
// indexed based on salted role names.
roleLocks []*locksutil.LockEntry
// Locks to make changes to the storage entries of RoleIDs generated. These
// will be initialized to a predefined number of locks when the backend is
// created, and will be indexed based on the salted RoleIDs.
roleIDLocks []*locksutil.LockEntry
// Locks to make changes to the storage entries of SecretIDs generated.
// These will be initialized to a predefined number of locks when the
// backend is created, and will be indexed based on the HMAC-ed SecretIDs.
secretIDLocks []*locksutil.LockEntry
// Locks to make changes to the storage entries of SecretIDAccessors
// generated. These will be initialized to a predefined number of locks
// when the backend is created, and will be indexed based on the
// SecretIDAccessors itself.
secretIDAccessorLocks []*locksutil.LockEntry
// secretIDListingLock is a dedicated lock for listing SecretIDAccessors
// for all the SecretIDs issued against an approle
secretIDListingLock sync.RWMutex
}
func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) {
b, err := Backend(conf)
if err != nil {
return nil, err
}
if err := b.Setup(ctx, conf); err != nil {
return nil, err
}
return b, nil
}
func Backend(conf *logical.BackendConfig) (*backend, error) {
// Create a backend object
b := &backend{
view: conf.StorageView,
// Create locks to modify the registered roles
roleLocks: locksutil.CreateLocks(),
// Create locks to modify the generated RoleIDs
roleIDLocks: locksutil.CreateLocks(),
// Create locks to modify the generated SecretIDs
secretIDLocks: locksutil.CreateLocks(),
// Create locks to modify the generated SecretIDAccessors
secretIDAccessorLocks: locksutil.CreateLocks(),
tidySecretIDCASGuard: new(uint32),
}
// Attach the paths and secrets that are to be handled by the backend
b.Backend = &framework.Backend{
// Register a periodic function that deletes the expired SecretID entries
PeriodicFunc: b.periodicFunc,
Help: backendHelp,
AuthRenew: b.pathLoginRenew,
PathsSpecial: &logical.Paths{
Unauthenticated: []string{
"login",
},
LocalStorage: []string{
secretIDLocalPrefix,
secretIDAccessorLocalPrefix,
},
SealWrapStorage: []string{
secretIDPrefix,
secretIDLocalPrefix,
},
},
Paths: framework.PathAppend(
rolePaths(b),
[]*framework.Path{
pathLogin(b),
pathTidySecretID(b),
},
),
Invalidate: b.invalidate,
BackendType: logical.TypeCredential,
RunningVersion: ReportedVersion,
}
return b, nil
}
func (b *backend) Salt(ctx context.Context) (*salt.Salt, error) {
b.saltMutex.RLock()
if b.salt != nil {
defer b.saltMutex.RUnlock()
return b.salt, nil
}
b.saltMutex.RUnlock()
b.saltMutex.Lock()
defer b.saltMutex.Unlock()
if b.salt != nil {
return b.salt, nil
}
salt, err := salt.NewSalt(ctx, b.view, &salt.Config{
HashFunc: salt.SHA256Hash,
Location: salt.DefaultLocation,
})
if err != nil {
return nil, err
}
b.salt = salt
return salt, nil
}
func (b *backend) invalidate(_ context.Context, key string) {
switch key {
case salt.DefaultLocation:
b.saltMutex.Lock()
defer b.saltMutex.Unlock()
b.salt = nil
}
}
// periodicFunc of the backend will be invoked once a minute by the RollbackManager.
// RoleRole backend utilizes this function to delete expired SecretID entries.
// This could mean that the SecretID may live in the backend upto 1 min after its
// expiration. The deletion of SecretIDs are not security sensitive and it is okay
// to delay the removal of SecretIDs by a minute.
func (b *backend) periodicFunc(ctx context.Context, req *logical.Request) error {
// Initiate clean-up of expired SecretID entries
if b.System().LocalMount() || !b.System().ReplicationState().HasState(consts.ReplicationPerformanceSecondary|consts.ReplicationPerformanceStandby) {
b.tidySecretID(ctx, req)
}
return nil
}
const backendHelp = `
Any registered Role can authenticate itself with Vault. The credentials
depends on the constraints that are set on the Role. One common required
credential is the 'role_id' which is a unique identifier of the Role.
It can be retrieved from the 'role/<appname>/role-id' endpoint.
The default constraint configuration is 'bind_secret_id', which requires
the credential 'secret_id' to be presented during login. Refer to the
documentation for other types of constraints.`