Skip to content

Commit 5f17953

Browse files
authored
MFA (#14049)
* adds development workflow to mirage config * adds mirage handler and factory for mfa workflow * adds mfa handling to auth service and cluster adapter * moves auth success logic from form to controller * adds mfa form component * shows delayed auth message for all methods * adds new code delay to mfa form * adds error views * fixes merge conflict * adds integration tests for mfa-form component * fixes auth tests * updates mfa response handling to align with backend * updates mfa-form to handle multiple methods and constraints * adds noDefault arg to Select component * updates mirage mfa handler to align with backend and adds generator for various mfa scenarios * adds tests * flaky test fix attempt * reverts test fix attempt * adds changelog entry * updates comments for todo items * removes faker from mfa mirage factory and handler * adds number to word helper * fixes tests * Revert "Merge branch 'main' into ui/mfa" This reverts commit 8ee6a6a, reversing changes made to 2428dd6. * format-ttl helper fix from main
1 parent 1aa506e commit 5f17953

File tree

80 files changed

+1397
-1118
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

80 files changed

+1397
-1118
lines changed

api/client.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ const (
5151
EnvRateLimit = "VAULT_RATE_LIMIT"
5252
EnvHTTPProxy = "VAULT_HTTP_PROXY"
5353
HeaderIndex = "X-Vault-Index"
54-
HeaderForward = "X-Vault-Forward"
55-
HeaderInconsistent = "X-Vault-Inconsistent"
5654
)
5755

5856
// Deprecated values
@@ -1397,7 +1395,7 @@ func ParseReplicationState(raw string, hmacKey []byte) (*logical.WALState, error
13971395
// conjunction with RequireState.
13981396
func ForwardInconsistent() RequestCallback {
13991397
return func(req *Request) {
1400-
req.Headers.Set(HeaderInconsistent, "forward-active-node")
1398+
req.Headers.Set("X-Vault-Inconsistent", "forward-active-node")
14011399
}
14021400
}
14031401

@@ -1406,7 +1404,7 @@ func ForwardInconsistent() RequestCallback {
14061404
// This feature must be enabled in Vault's configuration.
14071405
func ForwardAlways() RequestCallback {
14081406
return func(req *Request) {
1409-
req.Headers.Set(HeaderForward, "active-node")
1407+
req.Headers.Set("X-Vault-Forward", "active-node")
14101408
}
14111409
}
14121410

api/sys_mounts.go

Lines changed: 4 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"errors"
66
"fmt"
7-
"time"
87

98
"github.com/mitchellh/mapstructure"
109
)
@@ -66,91 +65,24 @@ func (c *Sys) Unmount(path string) error {
6665
return err
6766
}
6867

69-
// Remount kicks off a remount operation, polls the status endpoint using
70-
// the migration ID till either success or failure state is observed
7168
func (c *Sys) Remount(from, to string) error {
72-
remountResp, err := c.StartRemount(from, to)
73-
if err != nil {
74-
return err
75-
}
76-
77-
for {
78-
remountStatusResp, err := c.RemountStatus(remountResp.MigrationID)
79-
if err != nil {
80-
return err
81-
}
82-
if remountStatusResp.MigrationInfo.MigrationStatus == "success" {
83-
return nil
84-
}
85-
if remountStatusResp.MigrationInfo.MigrationStatus == "failure" {
86-
return fmt.Errorf("Failure! Error encountered moving mount %s to %s, with migration ID %s", from, to, remountResp.MigrationID)
87-
}
88-
time.Sleep(1 * time.Second)
89-
}
90-
}
91-
92-
// StartRemount kicks off a mount migration and returns a response with the migration ID
93-
func (c *Sys) StartRemount(from, to string) (*MountMigrationOutput, error) {
9469
body := map[string]interface{}{
9570
"from": from,
9671
"to": to,
9772
}
9873

9974
r := c.c.NewRequest("POST", "/v1/sys/remount")
10075
if err := r.SetJSONBody(body); err != nil {
101-
return nil, err
76+
return err
10277
}
10378

10479
ctx, cancelFunc := context.WithCancel(context.Background())
10580
defer cancelFunc()
10681
resp, err := c.c.RawRequestWithContext(ctx, r)
107-
if err != nil {
108-
return nil, err
109-
}
110-
defer resp.Body.Close()
111-
secret, err := ParseSecret(resp.Body)
112-
if err != nil {
113-
return nil, err
114-
}
115-
if secret == nil || secret.Data == nil {
116-
return nil, errors.New("data from server response is empty")
117-
}
118-
119-
var result MountMigrationOutput
120-
err = mapstructure.Decode(secret.Data, &result)
121-
if err != nil {
122-
return nil, err
123-
}
124-
125-
return &result, err
126-
}
127-
128-
// RemountStatus checks the status of a mount migration operation with the provided ID
129-
func (c *Sys) RemountStatus(migrationID string) (*MountMigrationStatusOutput, error) {
130-
r := c.c.NewRequest("GET", fmt.Sprintf("/v1/sys/remount/status/%s", migrationID))
131-
132-
ctx, cancelFunc := context.WithCancel(context.Background())
133-
defer cancelFunc()
134-
resp, err := c.c.RawRequestWithContext(ctx, r)
135-
if err != nil {
136-
return nil, err
137-
}
138-
defer resp.Body.Close()
139-
secret, err := ParseSecret(resp.Body)
140-
if err != nil {
141-
return nil, err
142-
}
143-
if secret == nil || secret.Data == nil {
144-
return nil, errors.New("data from server response is empty")
145-
}
146-
147-
var result MountMigrationStatusOutput
148-
err = mapstructure.Decode(secret.Data, &result)
149-
if err != nil {
150-
return nil, err
82+
if err == nil {
83+
defer resp.Body.Close()
15184
}
152-
153-
return &result, err
85+
return err
15486
}
15587

15688
func (c *Sys) TuneMount(path string, config MountConfigInput) error {
@@ -255,18 +187,3 @@ type MountConfigOutput struct {
255187
// Deprecated: This field will always be blank for newer server responses.
256188
PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"`
257189
}
258-
259-
type MountMigrationOutput struct {
260-
MigrationID string `mapstructure:"migration_id"`
261-
}
262-
263-
type MountMigrationStatusOutput struct {
264-
MigrationID string `mapstructure:"migration_id"`
265-
MigrationInfo *MountMigrationStatusInfo `mapstructure:"migration_info"`
266-
}
267-
268-
type MountMigrationStatusInfo struct {
269-
SourceMount string `mapstructure:"source_mount"`
270-
TargetMount string `mapstructure:"target_mount"`
271-
MigrationStatus string `mapstructure:"status"`
272-
}

builtin/credential/approle/path_login.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -178,14 +178,11 @@ func (b *backend) pathLoginUpdate(ctx context.Context, req *logical.Request, dat
178178
}
179179

180180
belongs, err := cidrutil.IPBelongsToCIDRBlocksSlice(req.Connection.RemoteAddr, entry.CIDRList)
181-
if err != nil {
182-
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
183-
}
184-
185-
if !belongs {
181+
if !belongs || err != nil {
186182
return logical.ErrorResponse(fmt.Errorf(
187-
"source address %q unauthorized through CIDR restrictions on the secret ID",
183+
"source address %q unauthorized through CIDR restrictions on the secret ID: %w",
188184
req.Connection.RemoteAddr,
185+
err,
189186
).Error()), nil
190187
}
191188
}

builtin/logical/ssh/path_config_ca.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,13 @@ import (
1010
"crypto/rsa"
1111
"crypto/x509"
1212
"encoding/pem"
13-
"errors"
1413
"fmt"
1514
"io"
1615

1716
multierror "github.com/hashicorp/go-multierror"
1817
"github.com/hashicorp/vault/sdk/framework"
1918
"github.com/hashicorp/vault/sdk/logical"
2019
"golang.org/x/crypto/ssh"
21-
22-
"github.com/mikesmitty/edkey"
2320
)
2421

2522
const (
@@ -360,9 +357,9 @@ func generateSSHKeyPair(randomSource io.Reader, keyType string, keyBits int) (st
360357
return "", "", err
361358
}
362359

363-
marshalled := edkey.MarshalED25519PrivateKey(privateSeed)
364-
if marshalled == nil {
365-
return "", "", errors.New("unable to marshal ed25519 private key")
360+
marshalled, err := x509.MarshalPKCS8PrivateKey(privateSeed)
361+
if err != nil {
362+
return "", "", err
366363
}
367364

368365
privateBlock = &pem.Block{

builtin/logical/ssh/path_config_ca_test.go

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -191,31 +191,17 @@ func createDeleteHelper(t *testing.T, b logical.Backend, config *logical.Backend
191191
}
192192
resp, err := b.HandleRequest(context.Background(), caReq)
193193
if err != nil || (resp != nil && resp.IsError()) {
194-
t.Fatalf("bad case %v: err: %v, resp: %v", index, err, resp)
194+
t.Fatalf("bad case %v: err: %v, resp:%v", index, err, resp)
195195
}
196196
if !strings.Contains(resp.Data["public_key"].(string), caReq.Data["key_type"].(string)) {
197197
t.Fatalf("bad case %v: expected public key of type %v but was %v", index, caReq.Data["key_type"], resp.Data["public_key"])
198198
}
199199

200-
issueOptions := map[string]interface{}{
201-
"public_key": testCAPublicKeyEd25519,
202-
}
203-
issueReq := &logical.Request{
204-
Path: "sign/ca-issuance",
205-
Operation: logical.UpdateOperation,
206-
Storage: config.StorageView,
207-
Data: issueOptions,
208-
}
209-
resp, err = b.HandleRequest(context.Background(), issueReq)
210-
if err != nil || (resp != nil && resp.IsError()) {
211-
t.Fatalf("bad case %v: err: %v, resp: %v", index, err, resp)
212-
}
213-
214200
// Delete the configured keys
215201
caReq.Operation = logical.DeleteOperation
216202
resp, err = b.HandleRequest(context.Background(), caReq)
217203
if err != nil || (resp != nil && resp.IsError()) {
218-
t.Fatalf("bad case %v: err: %v, resp: %v", index, err, resp)
204+
t.Fatalf("bad case %v: err: %v, resp:%v", index, err, resp)
219205
}
220206
}
221207

@@ -249,24 +235,6 @@ func TestSSH_ConfigCAKeyTypes(t *testing.T) {
249235
{"ed25519", 0},
250236
}
251237

252-
// Create a role for ssh signing.
253-
roleOptions := map[string]interface{}{
254-
"allow_user_certificates": true,
255-
"allowed_users": "*",
256-
"key_type": "ca",
257-
"ttl": "30s",
258-
}
259-
roleReq := &logical.Request{
260-
Operation: logical.UpdateOperation,
261-
Path: "roles/ca-issuance",
262-
Data: roleOptions,
263-
Storage: config.StorageView,
264-
}
265-
_, err = b.HandleRequest(context.Background(), roleReq)
266-
if err != nil {
267-
t.Fatalf("Cannot create role to issue against: %s", err)
268-
}
269-
270238
for index, scenario := range cases {
271239
createDeleteHelper(t, b, config, index, scenario.keyType, scenario.keyBits)
272240
}

builtin/logical/transit/backend.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ func (b *backend) periodicFunc(ctx context.Context, req *logical.Request) error
190190
}
191191

192192
// autoRotateKeys retrieves all transit keys and rotates those which have an
193-
// auto rotate period defined which has passed. This operation only happens
193+
// auto rotate interval defined which has passed. This operation only happens
194194
// on primary nodes and performance secondary nodes which have a local mount.
195195
func (b *backend) autoRotateKeys(ctx context.Context, req *logical.Request) error {
196196
// Only check for autorotation once an hour to avoid unnecessarily iterating
@@ -247,15 +247,15 @@ func (b *backend) rotateIfRequired(ctx context.Context, req *logical.Request, ke
247247
}
248248
defer p.Unlock()
249249

250-
// If the policy's automatic rotation period is 0, it should not
250+
// If the policy's automatic rotation interval is 0, it should not
251251
// automatically rotate.
252-
if p.AutoRotatePeriod == 0 {
252+
if p.AutoRotateInterval == 0 {
253253
return nil
254254
}
255255

256256
// Retrieve the latest version of the policy and determine if it is time to rotate.
257257
latestKey := p.Keys[strconv.Itoa(p.LatestVersion)]
258-
if time.Now().After(latestKey.CreationTime.Add(p.AutoRotatePeriod)) {
258+
if time.Now().After(latestKey.CreationTime.Add(p.AutoRotateInterval)) {
259259
if b.Logger().IsDebug() {
260260
b.Logger().Debug("automatically rotating key", "key", key)
261261
}

builtin/logical/transit/backend_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1607,7 +1607,7 @@ func TestTransit_AutoRotateKeys(t *testing.T) {
16071607
Operation: logical.UpdateOperation,
16081608
Path: "keys/test2",
16091609
Data: map[string]interface{}{
1610-
"auto_rotate_period": 24 * time.Hour,
1610+
"auto_rotate_interval": 24 * time.Hour,
16111611
},
16121612
}
16131613
resp, err = b.HandleRequest(context.Background(), req)
@@ -1651,7 +1651,7 @@ func TestTransit_AutoRotateKeys(t *testing.T) {
16511651
t.Fatalf("incorrect latest_version found, got: %d, want: %d", resp.Data["latest_version"], 1)
16521652
}
16531653

1654-
// Update auto rotate period on one key to be one nanosecond
1654+
// Update auto rotate interval on one key to be one nanosecond
16551655
p, _, err := b.GetPolicy(context.Background(), keysutil.PolicyRequest{
16561656
Storage: storage,
16571657
Name: "test2",
@@ -1662,7 +1662,7 @@ func TestTransit_AutoRotateKeys(t *testing.T) {
16621662
if p == nil {
16631663
t.Fatal("expected non-nil policy")
16641664
}
1665-
p.AutoRotatePeriod = time.Nanosecond
1665+
p.AutoRotateInterval = time.Nanosecond
16661666
err = p.Persist(context.Background(), storage)
16671667
if err != nil {
16681668
t.Fatal(err)

builtin/logical/transit/path_config.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ the latest version of the key is allowed.`,
4949
Description: `Enables taking a backup of the named key in plaintext format. Once set, this cannot be disabled.`,
5050
},
5151

52-
"auto_rotate_period": {
52+
"auto_rotate_interval": {
5353
Type: framework.TypeDurationSecond,
5454
Description: `Amount of time the key should live before
5555
being automatically rotated. A value of 0
@@ -193,19 +193,19 @@ func (b *backend) pathConfigWrite(ctx context.Context, req *logical.Request, d *
193193
}
194194
}
195195

196-
autoRotatePeriodRaw, ok, err := d.GetOkErr("auto_rotate_period")
196+
autoRotateIntervalRaw, ok, err := d.GetOkErr("auto_rotate_interval")
197197
if err != nil {
198198
return nil, err
199199
}
200200
if ok {
201-
autoRotatePeriod := time.Second * time.Duration(autoRotatePeriodRaw.(int))
201+
autoRotateInterval := time.Second * time.Duration(autoRotateIntervalRaw.(int))
202202
// Provided value must be 0 to disable or at least an hour
203-
if autoRotatePeriod != 0 && autoRotatePeriod < time.Hour {
204-
return logical.ErrorResponse("auto rotate period must be 0 to disable or at least an hour"), nil
203+
if autoRotateInterval != 0 && autoRotateInterval < time.Hour {
204+
return logical.ErrorResponse("auto rotate interval must be 0 to disable or at least an hour"), nil
205205
}
206206

207-
if autoRotatePeriod != p.AutoRotatePeriod {
208-
p.AutoRotatePeriod = autoRotatePeriod
207+
if autoRotateInterval != p.AutoRotateInterval {
208+
p.AutoRotateInterval = autoRotateInterval
209209
persistNeeded = true
210210
}
211211
}

0 commit comments

Comments
 (0)