mirror of
https://github.com/hashicorp/vault.git
synced 2025-08-22 07:01:09 +02:00
* adding password to static roles * adding check for password rotation to disable password edit * update field type and tests * adding changelog * replacing readonly with enableinput, added disable arg, test updates * update to unless * PR comments
224 lines
6.4 KiB
JavaScript
224 lines
6.4 KiB
JavaScript
/**
|
||
* Copyright (c) HashiCorp, Inc.
|
||
* SPDX-License-Identifier: BUSL-1.1
|
||
*/
|
||
import Model, { attr } from '@ember-data/model';
|
||
import { service } from '@ember/service';
|
||
import lazyCapabilities, { apiPath } from 'vault/macros/lazy-capabilities';
|
||
import { getRoleFields } from 'vault/utils/model-helpers/database-helpers';
|
||
import { expandAttributeMeta } from 'vault/utils/field-to-attrs';
|
||
import { withModelValidations } from 'vault/decorators/model-validations';
|
||
const validations = {
|
||
name: [{ type: 'presence', message: 'Role name is required.' }],
|
||
database: [{ type: 'presence', message: 'Database is required.' }],
|
||
type: [{ type: 'presence', message: 'Type is required.' }],
|
||
username: [
|
||
{
|
||
validator(model) {
|
||
const { type, username } = model;
|
||
if (!type || type === 'dynamic') return true;
|
||
if (username) return true;
|
||
},
|
||
message: 'Username is required.',
|
||
},
|
||
],
|
||
};
|
||
@withModelValidations(validations)
|
||
export default class RoleModel extends Model {
|
||
@service version;
|
||
|
||
idPrefix = 'role/';
|
||
|
||
@attr('string', { readOnly: true }) backend;
|
||
|
||
@attr('string', { label: 'Role name' }) name;
|
||
|
||
@attr('array', {
|
||
label: 'Connection name',
|
||
editType: 'searchSelect',
|
||
fallbackComponent: 'string-list',
|
||
models: ['database/connection'],
|
||
selectLimit: 1,
|
||
onlyAllowExisting: true,
|
||
subText: 'The database connection for which credentials will be generated.',
|
||
})
|
||
database;
|
||
|
||
@attr('string', {
|
||
label: 'Type of role',
|
||
noDefault: true,
|
||
possibleValues: ['static', 'dynamic'],
|
||
})
|
||
type;
|
||
|
||
@attr({
|
||
editType: 'ttl',
|
||
defaultValue: '1h',
|
||
label: 'Generated credentials’s Time-to-Live (TTL)',
|
||
helperTextDisabled: 'Vault will use a TTL of 1 hour.',
|
||
defaultShown: 'Engine default',
|
||
})
|
||
default_ttl;
|
||
|
||
@attr({
|
||
editType: 'ttl',
|
||
defaultValue: '24h',
|
||
label: 'Generated credentials’s maximum Time-to-Live (Max TTL)',
|
||
helperTextDisabled: 'Vault will use a TTL of 24 hours.',
|
||
defaultShown: 'Engine default',
|
||
})
|
||
max_ttl;
|
||
|
||
@attr('string', { subText: 'The database username that this Vault role corresponds to.' }) username;
|
||
|
||
@attr({
|
||
editType: 'ttl',
|
||
defaultValue: '24h',
|
||
helperTextDisabled:
|
||
'Specifies the amount of time Vault should wait before rotating the password. The minimum is 5 seconds. Default is 24 hours.',
|
||
helperTextEnabled: 'Vault will rotate password after.',
|
||
})
|
||
rotation_period;
|
||
|
||
@attr('array', {
|
||
editType: 'stringArray',
|
||
})
|
||
creation_statements;
|
||
|
||
@attr('array', {
|
||
editType: 'stringArray',
|
||
defaultShown: 'Default',
|
||
})
|
||
revocation_statements;
|
||
|
||
@attr('array', {
|
||
editType: 'stringArray',
|
||
defaultShown: 'Default',
|
||
})
|
||
rotation_statements;
|
||
|
||
@attr('array', {
|
||
editType: 'stringArray',
|
||
defaultShown: 'Default',
|
||
})
|
||
rollback_statements;
|
||
|
||
@attr('array', {
|
||
editType: 'stringArray',
|
||
defaultShown: 'Default',
|
||
})
|
||
renew_statements;
|
||
|
||
@attr('string', {
|
||
editType: 'json',
|
||
allowReset: true,
|
||
theme: 'hashi short',
|
||
defaultShown: 'Default',
|
||
})
|
||
creation_statement;
|
||
|
||
@attr('string', {
|
||
editType: 'json',
|
||
allowReset: true,
|
||
theme: 'hashi short',
|
||
defaultShown: 'Default',
|
||
})
|
||
revocation_statement;
|
||
|
||
@attr('string', { readOnly: true }) last_vault_rotation;
|
||
|
||
// ENTERPRISE ONLY
|
||
@attr({
|
||
label: 'Rotate immediately',
|
||
editType: 'toggleButton',
|
||
helperTextEnabled: 'Vault will rotate the password for this static role on creation.',
|
||
helperTextDisabled: "Vault will not rotate this role's password on creation.",
|
||
isOppositeValue: true,
|
||
})
|
||
skip_import_rotation;
|
||
|
||
@attr('string', {
|
||
sensitive: true,
|
||
subText: 'The database password that this Vault role corresponds to.',
|
||
})
|
||
password;
|
||
|
||
/* FIELD ATTRIBUTES */
|
||
get fieldAttrs() {
|
||
// Main fields on edit/create form
|
||
const fields = ['name', 'database', 'type'];
|
||
return expandAttributeMeta(this, fields);
|
||
}
|
||
get showFields() {
|
||
let fields = ['name', 'database', 'type'];
|
||
fields = fields.concat(getRoleFields(this.type)).concat(['creation_statements']);
|
||
// elasticsearch does not support revocation statements: https://developer.hashicorp.com/vault/api-docs/secret/databases/elasticdb#parameters-1
|
||
if (this.database[0] !== 'elasticsearch') {
|
||
fields = fields.concat(['revocation_statements']);
|
||
}
|
||
return expandAttributeMeta(this, fields);
|
||
}
|
||
get roleSettingAttrs() {
|
||
// logic for which get displayed is on DatabaseRoleSettingForm
|
||
let allRoleSettingFields = [
|
||
'default_ttl',
|
||
'max_ttl',
|
||
'username',
|
||
'password',
|
||
'rotation_period',
|
||
'skip_import_rotation',
|
||
'creation_statements',
|
||
'creation_statement', // for editType: JSON
|
||
'revocation_statements',
|
||
'revocation_statement', // only for MongoDB (editType: JSON)
|
||
'rotation_statements',
|
||
'rollback_statements',
|
||
'renew_statements',
|
||
];
|
||
|
||
// remove enterprise-only attrs if on community
|
||
if (!this.version.isEnterprise) {
|
||
allRoleSettingFields = allRoleSettingFields.filter(
|
||
(role) => !['skip_import_rotation', 'password'].includes(role)
|
||
);
|
||
}
|
||
|
||
return expandAttributeMeta(this, allRoleSettingFields);
|
||
}
|
||
/* CAPABILITIES */
|
||
// only used for secretPath
|
||
@attr('string', { readOnly: true }) path;
|
||
@lazyCapabilities(apiPath`${'backend'}/${'path'}/${'id'}`, 'backend', 'path', 'id') secretPath;
|
||
@lazyCapabilities(apiPath`${'backend'}/roles/+`, 'backend') dynamicPath;
|
||
@lazyCapabilities(apiPath`${'backend'}/static-roles/+`, 'backend') staticPath;
|
||
@lazyCapabilities(apiPath`${'backend'}/creds/${'id'}`, 'backend', 'id') credentialPath;
|
||
@lazyCapabilities(apiPath`${'backend'}/static-creds/${'id'}`, 'backend', 'id') staticCredentialPath;
|
||
@lazyCapabilities(apiPath`${'backend'}/config/${'database[0]'}`, 'backend', 'database') databasePath;
|
||
@lazyCapabilities(apiPath`${'backend'}/rotate-role/${'id'}`, 'backend', 'id') rotateRolePath;
|
||
|
||
get canEditRole() {
|
||
return this.secretPath.get('canUpdate');
|
||
}
|
||
get canDelete() {
|
||
return this.secretPath.get('canDelete');
|
||
}
|
||
get canCreateDynamic() {
|
||
return this.dynamicPath.get('canCreate');
|
||
}
|
||
get canCreateStatic() {
|
||
return this.staticPath.get('canCreate');
|
||
}
|
||
get canGenerateCredentials() {
|
||
return this.credentialPath.get('canRead');
|
||
}
|
||
get canGetCredentials() {
|
||
return this.staticCredentialPath.get('canRead');
|
||
}
|
||
get canUpdateDb() {
|
||
return this.databasePath.get('canUpdate');
|
||
}
|
||
get canRotateRoleCredentials() {
|
||
return this.rotateRolePath.get('canUpdate');
|
||
}
|
||
}
|