diff --git a/changelog/19791.txt b/changelog/19791.txt
new file mode 100644
index 000000000..26722cde3
--- /dev/null
+++ b/changelog/19791.txt
@@ -0,0 +1,3 @@
+```release-note:improvement
+ui: add allowed_managed_keys field to secret engine mount options
+```
diff --git a/ui/app/components/mount-backend-form.js b/ui/app/components/mount-backend-form.js
index 6fa141265..6b09f5e1f 100644
--- a/ui/app/components/mount-backend-form.js
+++ b/ui/app/components/mount-backend-form.js
@@ -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) {
const { isValid, state, invalidFormMessage } = model.validate();
this.modelValidations = state;
@@ -158,6 +169,7 @@ export default class MountBackendForm extends Component {
@action
setMountType(value) {
this.args.mountModel.type = value;
+ this.typeChangeSideEffect(value);
this.checkPathChange(value);
}
}
diff --git a/ui/app/decorators/model-expanded-attributes.js b/ui/app/decorators/model-expanded-attributes.js
index 60db028a3..a5aa840ba 100644
--- a/ui/app/decorators/model-expanded-attributes.js
+++ b/ui/app/decorators/model-expanded-attributes.js
@@ -73,7 +73,14 @@ export function withExpandedAttributes() {
});
const expanded = expandAttributeMeta(rModel, rAttrNames);
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._allByKey = byKey;
diff --git a/ui/app/helpers/mountable-secret-engines.js b/ui/app/helpers/mountable-secret-engines.js
index a771f4bd9..33f1228fe 100644
--- a/ui/app/helpers/mountable-secret-engines.js
+++ b/ui/app/helpers/mountable-secret-engines.js
@@ -87,6 +87,7 @@ const MOUNTABLE_SECRET_ENGINES = [
{
displayName: 'PKI Certificates',
type: 'pki',
+ // engineRoute: 'pki.overview', // TODO VAULT-13822
category: 'generic',
},
{
diff --git a/ui/app/models/mount-config.js b/ui/app/models/mount-config.js
index 54dd1f678..8f938b259 100644
--- a/ui/app/models/mount-config.js
+++ b/ui/app/models/mount-config.js
@@ -63,5 +63,8 @@ export default class MountConfigModel extends Model {
})
tokenType;
- @attr() allowedManagedKeys;
+ @attr({
+ editType: 'stringArray',
+ })
+ allowedManagedKeys;
}
diff --git a/ui/app/models/secret-engine.js b/ui/app/models/secret-engine.js
index 973429908..dbe083c4e 100644
--- a/ui/app/models/secret-engine.js
+++ b/ui/app/models/secret-engine.js
@@ -155,6 +155,7 @@ export default class SecretEngineModel extends Model {
fields.push('config.defaultLeaseTtl', 'config.maxLeaseTtl');
}
fields.push(
+ 'config.allowedManagedKeys',
'config.auditNonHmacRequestKeys',
'config.auditNonHmacResponseKeys',
'config.passthroughRequestHeaders',
@@ -189,6 +190,7 @@ export default class SecretEngineModel extends Model {
...CORE_OPTIONS,
'config.defaultLeaseTtl',
'config.maxLeaseTtl',
+ 'config.allowedManagedKeys',
...STANDARD_CONFIG,
];
break;
@@ -198,21 +200,32 @@ export default class SecretEngineModel extends Model {
...CORE_OPTIONS,
'config.defaultLeaseTtl',
'config.maxLeaseTtl',
+ 'config.allowedManagedKeys',
...STANDARD_CONFIG,
];
break;
case 'database':
// Highlight TTLs in default
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];
break;
case 'keymgmt':
// no ttl options for keymgmt
- optionFields = [...CORE_OPTIONS, ...STANDARD_CONFIG];
+ optionFields = [...CORE_OPTIONS, 'config.allowedManagedKeys', ...STANDARD_CONFIG];
break;
default:
defaultFields = ['path'];
- optionFields = [...CORE_OPTIONS, 'config.defaultLeaseTtl', 'config.maxLeaseTtl', ...STANDARD_CONFIG];
+ optionFields = [
+ ...CORE_OPTIONS,
+ 'config.defaultLeaseTtl',
+ 'config.maxLeaseTtl',
+ 'config.allowedManagedKeys',
+ ...STANDARD_CONFIG,
+ ];
break;
}
diff --git a/ui/app/templates/vault/cluster/secrets/backend/configuration.hbs b/ui/app/templates/vault/cluster/secrets/backend/configuration.hbs
index ba60af346..7890b5d31 100644
--- a/ui/app/templates/vault/cluster/secrets/backend/configuration.hbs
+++ b/ui/app/templates/vault/cluster/secrets/backend/configuration.hbs
@@ -29,13 +29,14 @@
{{else}}
{{/if}}
{{/each}}
diff --git a/ui/tests/acceptance/settings/mount-secret-backend-test.js b/ui/tests/acceptance/settings/mount-secret-backend-test.js
index a95509536..33c9152e5 100644
--- a/ui/tests/acceptance/settings/mount-secret-backend-test.js
+++ b/ui/tests/acceptance/settings/mount-secret-backend-test.js
@@ -32,8 +32,6 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) {
const path = `mount-kv-${this.uid}`;
const defaultTTLHours = 100;
const maxTTLHours = 300;
- const defaultTTLSeconds = (defaultTTLHours * 60 * 60).toString();
- const maxTTLSeconds = (maxTTLHours * 60 * 60).toString();
await page.visit();
@@ -51,15 +49,14 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) {
.maxTTLVal(maxTTLHours)
.submit();
await configPage.visit({ backend: path });
- assert.strictEqual(configPage.defaultTTL, `${defaultTTLSeconds}s`, 'shows the proper TTL');
- assert.strictEqual(configPage.maxTTL, `${maxTTLSeconds}s`, 'shows the proper max TTL');
+ assert.strictEqual(configPage.defaultTTL, `${defaultTTLHours}h`, 'shows the proper TTL');
+ assert.strictEqual(configPage.maxTTL, `${maxTTLHours}h`, 'shows the proper max TTL');
});
test('it sets the ttl when enabled then disabled', async function (assert) {
// always force the new mount to the top of the list
const path = `mount-kv-${this.uid}`;
const maxTTLHours = 300;
- const maxTTLSeconds = (maxTTLHours * 60 * 60).toString();
await page.visit();
@@ -76,8 +73,33 @@ module('Acceptance | settings/mount-secret-backend', function (hooks) {
.maxTTLVal(maxTTLHours)
.submit();
await configPage.visit({ backend: path });
- assert.strictEqual(configPage.defaultTTL, '0', 'shows the proper TTL');
- assert.strictEqual(configPage.maxTTL, `${maxTTLSeconds}s`, 'shows the proper max TTL');
+ assert.strictEqual(configPage.defaultTTL, '0s', 'shows the proper 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) {
diff --git a/ui/tests/pages/secrets/backend/configuration.js b/ui/tests/pages/secrets/backend/configuration.js
index 002512699..2ea641a0d 100644
--- a/ui/tests/pages/secrets/backend/configuration.js
+++ b/ui/tests/pages/secrets/backend/configuration.js
@@ -7,6 +7,6 @@ import { create, visitable, text } from 'ember-cli-page-object';
export default create({
visit: visitable('/vault/secrets/:backend/configuration'),
- defaultTTL: text('[data-test-row-value="Default Lease TTL"]'),
- maxTTL: text('[data-test-row-value="Max Lease TTL"]'),
+ defaultTTL: text('[data-test-value-div="Default Lease TTL"]'),
+ maxTTL: text('[data-test-value-div="Max Lease TTL"]'),
});
diff --git a/ui/tests/unit/models/secret-engine-test.js b/ui/tests/unit/models/secret-engine-test.js
index 1b977dbb6..c82a77efb 100644
--- a/ui/tests/unit/models/secret-engine-test.js
+++ b/ui/tests/unit/models/secret-engine-test.js
@@ -66,6 +66,7 @@ module('Unit | Model | secret-engine', function (hooks) {
'sealWrap',
'config.defaultLeaseTtl',
'config.maxLeaseTtl',
+ 'config.allowedManagedKeys',
'config.auditNonHmacRequestKeys',
'config.auditNonHmacResponseKeys',
'config.passthroughRequestHeaders',
@@ -88,6 +89,7 @@ module('Unit | Model | secret-engine', function (hooks) {
'sealWrap',
'config.defaultLeaseTtl',
'config.maxLeaseTtl',
+ 'config.allowedManagedKeys',
'config.auditNonHmacRequestKeys',
'config.auditNonHmacResponseKeys',
'config.passthroughRequestHeaders',
@@ -112,6 +114,7 @@ module('Unit | Model | secret-engine', function (hooks) {
'sealWrap',
'config.defaultLeaseTtl',
'config.maxLeaseTtl',
+ 'config.allowedManagedKeys',
'config.auditNonHmacRequestKeys',
'config.auditNonHmacResponseKeys',
'config.passthroughRequestHeaders',
@@ -136,6 +139,7 @@ module('Unit | Model | secret-engine', function (hooks) {
'accessor',
'local',
'sealWrap',
+ 'config.allowedManagedKeys',
'config.auditNonHmacRequestKeys',
'config.auditNonHmacResponseKeys',
'config.passthroughRequestHeaders',
@@ -161,6 +165,7 @@ module('Unit | Model | secret-engine', function (hooks) {
'sealWrap',
'config.defaultLeaseTtl',
'config.maxLeaseTtl',
+ 'config.allowedManagedKeys',
'config.auditNonHmacRequestKeys',
'config.auditNonHmacResponseKeys',
'config.passthroughRequestHeaders',
@@ -186,6 +191,7 @@ module('Unit | Model | secret-engine', function (hooks) {
'sealWrap',
'config.defaultLeaseTtl',
'config.maxLeaseTtl',
+ 'config.allowedManagedKeys',
'config.auditNonHmacRequestKeys',
'config.auditNonHmacResponseKeys',
'config.passthroughRequestHeaders',
@@ -212,6 +218,7 @@ module('Unit | Model | secret-engine', function (hooks) {
'sealWrap',
'config.defaultLeaseTtl',
'config.maxLeaseTtl',
+ 'config.allowedManagedKeys',
'config.auditNonHmacRequestKeys',
'config.auditNonHmacResponseKeys',
'config.passthroughRequestHeaders',
@@ -229,6 +236,30 @@ module('Unit | Model | secret-engine', function (hooks) {
assert.deepEqual(model.get('formFieldGroups'), [
{ 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': [
'description',
@@ -258,6 +289,7 @@ module('Unit | Model | secret-engine', function (hooks) {
'config.listingVisibility',
'local',
'sealWrap',
+ 'config.allowedManagedKeys',
'config.auditNonHmacRequestKeys',
'config.auditNonHmacResponseKeys',
'config.passthroughRequestHeaders',