UI: Mount PKI options + allowed_managed_keys (#19791)
This commit is contained in:
parent
43912fe0e2
commit
bb6964e18e
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:improvement
|
||||||
|
ui: add allowed_managed_keys field to secret engine mount options
|
||||||
|
```
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -63,5 +63,8 @@ export default class MountConfigModel extends Model {
|
||||||
})
|
})
|
||||||
tokenType;
|
tokenType;
|
||||||
|
|
||||||
@attr() allowedManagedKeys;
|
@attr({
|
||||||
|
editType: 'stringArray',
|
||||||
|
})
|
||||||
|
allowedManagedKeys;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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}}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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"]'),
|
||||||
});
|
});
|
||||||
|
|
|
@ -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',
|
||||||
|
|
Loading…
Reference in New Issue