UI: Mount PKI options + allowed_managed_keys (#19791)

This commit is contained in:
Chelsea Shaw 2023-04-07 16:05:29 -05:00 committed by GitHub
parent 43912fe0e2
commit bb6964e18e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 109 additions and 15 deletions

3
changelog/19791.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:improvement
ui: add allowed_managed_keys field to secret engine mount options
```

View File

@ -56,6 +56,17 @@ export default class MountBackendForm extends Component {
} }
} }
typeChangeSideEffect(type) {
if (!this.args.mountType === 'secret') return;
if (type === 'pki') {
// If type PKI, set max lease to ~10years
this.args.mountModel.config.maxLeaseTtl = '3650d';
} else {
// otherwise reset
this.args.mountModel.config.maxLeaseTtl = 0;
}
}
checkModelValidity(model) { checkModelValidity(model) {
const { isValid, state, invalidFormMessage } = model.validate(); const { isValid, state, invalidFormMessage } = model.validate();
this.modelValidations = state; this.modelValidations = state;
@ -158,6 +169,7 @@ export default class MountBackendForm extends Component {
@action @action
setMountType(value) { setMountType(value) {
this.args.mountModel.type = value; this.args.mountModel.type = value;
this.typeChangeSideEffect(value);
this.checkPathChange(value); this.checkPathChange(value);
} }
} }

View File

@ -73,7 +73,14 @@ export function withExpandedAttributes() {
}); });
const expanded = expandAttributeMeta(rModel, rAttrNames); const expanded = expandAttributeMeta(rModel, rAttrNames);
expanded.forEach((attr) => { expanded.forEach((attr) => {
byKey[`${name}.${attr.name}`] = attr; byKey[`${name}.${attr.name}`] = {
...attr,
options: {
...attr.options,
// This ensures the correct path is updated in FormField
fieldValue: `${name}.${attr.fieldValue || attr.name}`,
},
};
}); });
}, this); }, this);
this._allByKey = byKey; this._allByKey = byKey;

View File

@ -87,6 +87,7 @@ const MOUNTABLE_SECRET_ENGINES = [
{ {
displayName: 'PKI Certificates', displayName: 'PKI Certificates',
type: 'pki', type: 'pki',
// engineRoute: 'pki.overview', // TODO VAULT-13822
category: 'generic', category: 'generic',
}, },
{ {

View File

@ -63,5 +63,8 @@ export default class MountConfigModel extends Model {
}) })
tokenType; tokenType;
@attr() allowedManagedKeys; @attr({
editType: 'stringArray',
})
allowedManagedKeys;
} }

View File

@ -155,6 +155,7 @@ export default class SecretEngineModel extends Model {
fields.push('config.defaultLeaseTtl', 'config.maxLeaseTtl'); fields.push('config.defaultLeaseTtl', 'config.maxLeaseTtl');
} }
fields.push( fields.push(
'config.allowedManagedKeys',
'config.auditNonHmacRequestKeys', 'config.auditNonHmacRequestKeys',
'config.auditNonHmacResponseKeys', 'config.auditNonHmacResponseKeys',
'config.passthroughRequestHeaders', 'config.passthroughRequestHeaders',
@ -189,6 +190,7 @@ export default class SecretEngineModel extends Model {
...CORE_OPTIONS, ...CORE_OPTIONS,
'config.defaultLeaseTtl', 'config.defaultLeaseTtl',
'config.maxLeaseTtl', 'config.maxLeaseTtl',
'config.allowedManagedKeys',
...STANDARD_CONFIG, ...STANDARD_CONFIG,
]; ];
break; break;
@ -198,21 +200,32 @@ export default class SecretEngineModel extends Model {
...CORE_OPTIONS, ...CORE_OPTIONS,
'config.defaultLeaseTtl', 'config.defaultLeaseTtl',
'config.maxLeaseTtl', 'config.maxLeaseTtl',
'config.allowedManagedKeys',
...STANDARD_CONFIG, ...STANDARD_CONFIG,
]; ];
break; break;
case 'database': case 'database':
// Highlight TTLs in default // Highlight TTLs in default
defaultFields = ['path', 'config.defaultLeaseTtl', 'config.maxLeaseTtl']; defaultFields = ['path', 'config.defaultLeaseTtl', 'config.maxLeaseTtl'];
optionFields = [...CORE_OPTIONS, 'config.allowedManagedKeys', ...STANDARD_CONFIG];
break;
case 'pki':
defaultFields = ['path', 'config.defaultLeaseTtl', 'config.maxLeaseTtl', 'config.allowedManagedKeys'];
optionFields = [...CORE_OPTIONS, ...STANDARD_CONFIG]; optionFields = [...CORE_OPTIONS, ...STANDARD_CONFIG];
break; break;
case 'keymgmt': case 'keymgmt':
// no ttl options for keymgmt // no ttl options for keymgmt
optionFields = [...CORE_OPTIONS, ...STANDARD_CONFIG]; optionFields = [...CORE_OPTIONS, 'config.allowedManagedKeys', ...STANDARD_CONFIG];
break; break;
default: default:
defaultFields = ['path']; defaultFields = ['path'];
optionFields = [...CORE_OPTIONS, 'config.defaultLeaseTtl', 'config.maxLeaseTtl', ...STANDARD_CONFIG]; optionFields = [
...CORE_OPTIONS,
'config.defaultLeaseTtl',
'config.maxLeaseTtl',
'config.allowedManagedKeys',
...STANDARD_CONFIG,
];
break; break;
} }

View File

@ -29,13 +29,14 @@
<InfoTableRow <InfoTableRow
@alwaysRender={{not (is-empty-value (get this.model attr.name))}} @alwaysRender={{not (is-empty-value (get this.model attr.name))}}
@label={{or attr.options.label (to-label attr.name)}} @label={{or attr.options.label (to-label attr.name)}}
@value={{stringify (get this.model attr.name)}} @value={{stringify (get this.model (or attr.options.fieldValue attr.name))}}
/> />
{{else}} {{else}}
<InfoTableRow <InfoTableRow
@alwaysRender={{and (not (is-empty-value (get this.model attr.name))) (not-eq attr.name "version")}} @alwaysRender={{and (not (is-empty-value (get this.model attr.name))) (not-eq attr.name "version")}}
@formatTtl={{eq attr.options.editType "ttl"}}
@label={{or attr.options.label (to-label attr.name)}} @label={{or attr.options.label (to-label attr.name)}}
@value={{get this.model attr.name}} @value={{get this.model (or attr.options.fieldValue attr.name)}}
/> />
{{/if}} {{/if}}
{{/each}} {{/each}}

View File

@ -32,8 +32,6 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) {
const path = `mount-kv-${this.uid}`; const path = `mount-kv-${this.uid}`;
const defaultTTLHours = 100; const defaultTTLHours = 100;
const maxTTLHours = 300; const maxTTLHours = 300;
const defaultTTLSeconds = (defaultTTLHours * 60 * 60).toString();
const maxTTLSeconds = (maxTTLHours * 60 * 60).toString();
await page.visit(); await page.visit();
@ -51,15 +49,14 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) {
.maxTTLVal(maxTTLHours) .maxTTLVal(maxTTLHours)
.submit(); .submit();
await configPage.visit({ backend: path }); await configPage.visit({ backend: path });
assert.strictEqual(configPage.defaultTTL, `${defaultTTLSeconds}s`, 'shows the proper TTL'); assert.strictEqual(configPage.defaultTTL, `${defaultTTLHours}h`, 'shows the proper TTL');
assert.strictEqual(configPage.maxTTL, `${maxTTLSeconds}s`, 'shows the proper max TTL'); assert.strictEqual(configPage.maxTTL, `${maxTTLHours}h`, 'shows the proper max TTL');
}); });
test('it sets the ttl when enabled then disabled', async function (assert) { test('it sets the ttl when enabled then disabled', async function (assert) {
// always force the new mount to the top of the list // always force the new mount to the top of the list
const path = `mount-kv-${this.uid}`; const path = `mount-kv-${this.uid}`;
const maxTTLHours = 300; const maxTTLHours = 300;
const maxTTLSeconds = (maxTTLHours * 60 * 60).toString();
await page.visit(); await page.visit();
@ -76,8 +73,33 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) {
.maxTTLVal(maxTTLHours) .maxTTLVal(maxTTLHours)
.submit(); .submit();
await configPage.visit({ backend: path }); await configPage.visit({ backend: path });
assert.strictEqual(configPage.defaultTTL, '0', 'shows the proper TTL'); assert.strictEqual(configPage.defaultTTL, '0s', 'shows the proper TTL');
assert.strictEqual(configPage.maxTTL, `${maxTTLSeconds}s`, 'shows the proper max TTL'); assert.strictEqual(configPage.maxTTL, `${maxTTLHours}h`, 'shows the proper max TTL');
});
test('it sets the max ttl after pki chosen, resets after', async function (assert) {
await page.visit();
assert.strictEqual(currentRouteName(), 'vault.cluster.settings.mount-secret-backend');
await page.selectType('pki');
await page.next();
assert.dom('[data-test-input="maxLeaseTtl"]').exists();
assert
.dom('[data-test-input="maxLeaseTtl"] [data-test-ttl-toggle]')
.isChecked('Toggle is checked by default');
assert.dom('[data-test-input="maxLeaseTtl"] [data-test-ttl-value]').hasValue('3650');
assert.dom('[data-test-input="maxLeaseTtl"] [data-test-select="ttl-unit"]').hasValue('d');
// Go back and choose a different type
await page.back();
await page.selectType('database');
await page.next();
assert.dom('[data-test-input="maxLeaseTtl"]').exists('3650');
assert
.dom('[data-test-input="maxLeaseTtl"] [data-test-ttl-toggle]')
.isNotChecked('Toggle is unchecked by default');
await page.enableMaxTtl();
assert.dom('[data-test-input="maxLeaseTtl"] [data-test-ttl-value]').hasValue('');
assert.dom('[data-test-input="maxLeaseTtl"] [data-test-select="ttl-unit"]').hasValue('s');
}); });
test('it throws error if setting duplicate path name', async function (assert) { test('it throws error if setting duplicate path name', async function (assert) {

View File

@ -7,6 +7,6 @@ import { create, visitable, text } from 'ember-cli-page-object';
export default create({ export default create({
visit: visitable('/vault/secrets/:backend/configuration'), visit: visitable('/vault/secrets/:backend/configuration'),
defaultTTL: text('[data-test-row-value="Default Lease TTL"]'), defaultTTL: text('[data-test-value-div="Default Lease TTL"]'),
maxTTL: text('[data-test-row-value="Max Lease TTL"]'), maxTTL: text('[data-test-value-div="Max Lease TTL"]'),
}); });

View File

@ -66,6 +66,7 @@ module('Unit | Model | secret-engine', function (hooks) {
'sealWrap', 'sealWrap',
'config.defaultLeaseTtl', 'config.defaultLeaseTtl',
'config.maxLeaseTtl', 'config.maxLeaseTtl',
'config.allowedManagedKeys',
'config.auditNonHmacRequestKeys', 'config.auditNonHmacRequestKeys',
'config.auditNonHmacResponseKeys', 'config.auditNonHmacResponseKeys',
'config.passthroughRequestHeaders', 'config.passthroughRequestHeaders',
@ -88,6 +89,7 @@ module('Unit | Model | secret-engine', function (hooks) {
'sealWrap', 'sealWrap',
'config.defaultLeaseTtl', 'config.defaultLeaseTtl',
'config.maxLeaseTtl', 'config.maxLeaseTtl',
'config.allowedManagedKeys',
'config.auditNonHmacRequestKeys', 'config.auditNonHmacRequestKeys',
'config.auditNonHmacResponseKeys', 'config.auditNonHmacResponseKeys',
'config.passthroughRequestHeaders', 'config.passthroughRequestHeaders',
@ -112,6 +114,7 @@ module('Unit | Model | secret-engine', function (hooks) {
'sealWrap', 'sealWrap',
'config.defaultLeaseTtl', 'config.defaultLeaseTtl',
'config.maxLeaseTtl', 'config.maxLeaseTtl',
'config.allowedManagedKeys',
'config.auditNonHmacRequestKeys', 'config.auditNonHmacRequestKeys',
'config.auditNonHmacResponseKeys', 'config.auditNonHmacResponseKeys',
'config.passthroughRequestHeaders', 'config.passthroughRequestHeaders',
@ -136,6 +139,7 @@ module('Unit | Model | secret-engine', function (hooks) {
'accessor', 'accessor',
'local', 'local',
'sealWrap', 'sealWrap',
'config.allowedManagedKeys',
'config.auditNonHmacRequestKeys', 'config.auditNonHmacRequestKeys',
'config.auditNonHmacResponseKeys', 'config.auditNonHmacResponseKeys',
'config.passthroughRequestHeaders', 'config.passthroughRequestHeaders',
@ -161,6 +165,7 @@ module('Unit | Model | secret-engine', function (hooks) {
'sealWrap', 'sealWrap',
'config.defaultLeaseTtl', 'config.defaultLeaseTtl',
'config.maxLeaseTtl', 'config.maxLeaseTtl',
'config.allowedManagedKeys',
'config.auditNonHmacRequestKeys', 'config.auditNonHmacRequestKeys',
'config.auditNonHmacResponseKeys', 'config.auditNonHmacResponseKeys',
'config.passthroughRequestHeaders', 'config.passthroughRequestHeaders',
@ -186,6 +191,7 @@ module('Unit | Model | secret-engine', function (hooks) {
'sealWrap', 'sealWrap',
'config.defaultLeaseTtl', 'config.defaultLeaseTtl',
'config.maxLeaseTtl', 'config.maxLeaseTtl',
'config.allowedManagedKeys',
'config.auditNonHmacRequestKeys', 'config.auditNonHmacRequestKeys',
'config.auditNonHmacResponseKeys', 'config.auditNonHmacResponseKeys',
'config.passthroughRequestHeaders', 'config.passthroughRequestHeaders',
@ -212,6 +218,7 @@ module('Unit | Model | secret-engine', function (hooks) {
'sealWrap', 'sealWrap',
'config.defaultLeaseTtl', 'config.defaultLeaseTtl',
'config.maxLeaseTtl', 'config.maxLeaseTtl',
'config.allowedManagedKeys',
'config.auditNonHmacRequestKeys', 'config.auditNonHmacRequestKeys',
'config.auditNonHmacResponseKeys', 'config.auditNonHmacResponseKeys',
'config.passthroughRequestHeaders', 'config.passthroughRequestHeaders',
@ -229,6 +236,30 @@ module('Unit | Model | secret-engine', function (hooks) {
assert.deepEqual(model.get('formFieldGroups'), [ assert.deepEqual(model.get('formFieldGroups'), [
{ default: ['path', 'config.defaultLeaseTtl', 'config.maxLeaseTtl'] }, { default: ['path', 'config.defaultLeaseTtl', 'config.maxLeaseTtl'] },
{
'Method Options': [
'description',
'config.listingVisibility',
'local',
'sealWrap',
'config.allowedManagedKeys',
'config.auditNonHmacRequestKeys',
'config.auditNonHmacResponseKeys',
'config.passthroughRequestHeaders',
'config.allowedResponseHeaders',
],
},
]);
});
test('returns correct values for pki', function (assert) {
assert.expect(1);
const model = this.store.createRecord('secret-engine', {
type: 'pki',
});
assert.deepEqual(model.get('formFieldGroups'), [
{ default: ['path', 'config.defaultLeaseTtl', 'config.maxLeaseTtl', 'config.allowedManagedKeys'] },
{ {
'Method Options': [ 'Method Options': [
'description', 'description',
@ -258,6 +289,7 @@ module('Unit | Model | secret-engine', function (hooks) {
'config.listingVisibility', 'config.listingVisibility',
'local', 'local',
'sealWrap', 'sealWrap',
'config.allowedManagedKeys',
'config.auditNonHmacRequestKeys', 'config.auditNonHmacRequestKeys',
'config.auditNonHmacResponseKeys', 'config.auditNonHmacResponseKeys',
'config.passthroughRequestHeaders', 'config.passthroughRequestHeaders',