mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-29 17:52:32 +00:00
Sync Destination Updates (#25571)
* normalizes sync destination granularity key in serializer * adds new fields to aws and gcp sync destinations * updates sync destination delete action from destinations list view to route to overview on success * updates destination serializer normalize to check if options is defined
This commit is contained in:
@@ -13,13 +13,17 @@ const displayFields = [
|
||||
'region',
|
||||
'accessKeyId',
|
||||
'secretAccessKey',
|
||||
'roleArn',
|
||||
'externalId',
|
||||
// sync config options
|
||||
'granularity',
|
||||
'secretNameTemplate',
|
||||
'customTags',
|
||||
];
|
||||
const formFieldGroups = [
|
||||
{ default: ['name', 'region', 'granularity', 'secretNameTemplate', 'customTags'] },
|
||||
{
|
||||
default: ['name', 'region', 'roleArn', 'externalId', 'granularity', 'secretNameTemplate', 'customTags'],
|
||||
},
|
||||
{ Credentials: ['accessKeyId', 'secretAccessKey'] },
|
||||
];
|
||||
@withFormFields(displayFields, formFieldGroups)
|
||||
@@ -51,4 +55,18 @@ export default class SyncDestinationsAwsSecretsManagerModel extends SyncDestinat
|
||||
editType: 'kv',
|
||||
})
|
||||
customTags;
|
||||
|
||||
@attr('string', {
|
||||
label: 'Role ARN',
|
||||
subText:
|
||||
'Specifies a role to assume when connecting to AWS. When assuming a role, Vault uses temporary STS credentials to authenticate.',
|
||||
})
|
||||
roleArn;
|
||||
|
||||
@attr('string', {
|
||||
label: 'External ID',
|
||||
subText:
|
||||
'Optional extra protection that must match the trust policy granting access to the AWS IAM role ARN. We recommend using a different random UUID per destination.',
|
||||
})
|
||||
externalId;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import { withFormFields } from 'vault/decorators/model-form-fields';
|
||||
const displayFields = [
|
||||
// connection details
|
||||
'name',
|
||||
'projectId',
|
||||
'credentials',
|
||||
// vault sync config options
|
||||
'granularity',
|
||||
@@ -17,11 +18,18 @@ const displayFields = [
|
||||
'customTags',
|
||||
];
|
||||
const formFieldGroups = [
|
||||
{ default: ['name', 'granularity', 'secretNameTemplate', 'customTags'] },
|
||||
{ default: ['name', 'projectId', 'granularity', 'secretNameTemplate', 'customTags'] },
|
||||
{ Credentials: ['credentials'] },
|
||||
];
|
||||
@withFormFields(displayFields, formFieldGroups)
|
||||
export default class SyncDestinationsGoogleCloudSecretManagerModel extends SyncDestinationModel {
|
||||
@attr('string', {
|
||||
label: 'Project ID',
|
||||
subText:
|
||||
'The target project to manage secrets in. If set, overrides the project derived from the service account JSON credentials or application default credentials.',
|
||||
})
|
||||
projectId;
|
||||
|
||||
@attr('string', {
|
||||
label: 'JSON credentials',
|
||||
subText:
|
||||
|
||||
@@ -68,6 +68,11 @@ export default class SyncDestinationSerializer extends ApplicationSerializer {
|
||||
data.id = data.name;
|
||||
delete data.connection_details;
|
||||
delete data.options;
|
||||
// granularity keys differ from payload to response -- normalize to payload format
|
||||
if (options) {
|
||||
options.granularity = options.granularity_level;
|
||||
delete options.granularity_level;
|
||||
}
|
||||
return { data: { ...data, ...connection_details, ...options } };
|
||||
}
|
||||
return payload;
|
||||
|
||||
@@ -95,11 +95,11 @@ export default class SyncSecretsDestinationsPageComponent extends Component<Args
|
||||
@action
|
||||
async onDelete(destination: SyncDestinationModel) {
|
||||
try {
|
||||
const { name, type } = destination;
|
||||
const { name } = destination;
|
||||
const message = `Destination ${name} has been queued for deletion.`;
|
||||
await destination.destroyRecord();
|
||||
this.store.clearDataset('sync/destination');
|
||||
this.router.transitionTo('vault.cluster.sync.secrets.destinations.destination.secrets', type, name);
|
||||
this.router.transitionTo('vault.cluster.sync.secrets.overview');
|
||||
this.flashMessages.success(message);
|
||||
} catch (error) {
|
||||
this.flashMessages.danger(`Error deleting destination \n ${errorMessage(error)}`);
|
||||
|
||||
@@ -13,9 +13,11 @@ export default Factory.extend({
|
||||
access_key_id: '*****',
|
||||
secret_access_key: '*****',
|
||||
region: 'us-west-1',
|
||||
role_arn: 'test-role',
|
||||
external_id: 'id12345',
|
||||
// options
|
||||
granularity: 'secret-path', // default option (same for all destinations) so edit test can update to 'secret-key'
|
||||
secret_name_template: 'vault-{{ .MountAccessor | replace "_" "-" }}-{{ .SecretPath }}',
|
||||
secret_name_template: 'vault-{{ .MountAccessor }}-{{ .SecretPath }}',
|
||||
custom_tags: { foo: 'bar' },
|
||||
}),
|
||||
['azure-kv']: trait({
|
||||
@@ -30,17 +32,18 @@ export default Factory.extend({
|
||||
cloud: 'Azure Public Cloud',
|
||||
// options
|
||||
granularity: 'secret-path',
|
||||
secret_name_template: 'vault-{{ .MountAccessor | replace "_" "-" }}-{{ .SecretPath }}',
|
||||
secret_name_template: 'vault-{{ .MountAccessor }}-{{ .SecretPath }}',
|
||||
custom_tags: { foo: 'bar' },
|
||||
}),
|
||||
['gcp-sm']: trait({
|
||||
type: 'gcp-sm',
|
||||
name: 'destination-gcp',
|
||||
project_id: 'id12345',
|
||||
// connection_details
|
||||
credentials: '*****',
|
||||
// options
|
||||
granularity: 'secret-path',
|
||||
secret_name_template: 'vault-{{ .MountAccessor | replace "_" "-" }}-{{ .SecretPath }}',
|
||||
secret_name_template: 'vault-{{ .MountAccessor }}-{{ .SecretPath }}',
|
||||
custom_tags: { foo: 'bar' },
|
||||
}),
|
||||
gh: trait({
|
||||
@@ -52,7 +55,7 @@ export default Factory.extend({
|
||||
repository_name: 'my-repository',
|
||||
// options
|
||||
granularity: 'secret-path',
|
||||
secret_name_template: 'vault-{{ .MountAccessor | replace "_" "-" }}-{{ .SecretPath }}',
|
||||
secret_name_template: 'vault-{{ .MountAccessor }}-{{ .SecretPath }}',
|
||||
}),
|
||||
['vercel-project']: trait({
|
||||
type: 'vercel-project',
|
||||
@@ -63,6 +66,6 @@ export default Factory.extend({
|
||||
team_id: 'team_12345',
|
||||
deployment_environments: ['development', 'preview'], // 'production' is also an option, but left out for testing to assert form changes value
|
||||
// options
|
||||
secret_name_template: 'vault-{{ .MountAccessor | replace "_" "-" }}-{{ .SecretPath }}',
|
||||
secret_name_template: 'vault-{{ .MountAccessor }}-{{ .SecretPath }}',
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -154,7 +154,7 @@ module('Integration | Component | sync | Page::Destinations', function (hooks) {
|
||||
|
||||
assert.propEqual(
|
||||
this.transitionStub.lastCall.args,
|
||||
['vault.cluster.sync.secrets.destinations.destination.secrets', 'aws-sm', 'destination-aws'],
|
||||
['vault.cluster.sync.secrets.overview'],
|
||||
'Transition is triggered on delete success'
|
||||
);
|
||||
assert.propEqual(
|
||||
|
||||
@@ -270,9 +270,17 @@ module('Integration | Component | sync | Secrets::Page::Destinations::CreateAndE
|
||||
// if it is not a string type, add case to EXPECTED_VALUE and update
|
||||
// fillInByAttr() (in sync-selectors) to interact with the form
|
||||
const EDITABLE_FIELDS = {
|
||||
'aws-sm': ['accessKeyId', 'secretAccessKey', 'granularity', 'secretNameTemplate', 'customTags'],
|
||||
'aws-sm': [
|
||||
'accessKeyId',
|
||||
'secretAccessKey',
|
||||
'roleArn',
|
||||
'externalId',
|
||||
'granularity',
|
||||
'secretNameTemplate',
|
||||
'customTags',
|
||||
],
|
||||
'azure-kv': ['clientId', 'clientSecret', 'granularity', 'secretNameTemplate', 'customTags'],
|
||||
'gcp-sm': ['credentials', 'granularity', 'secretNameTemplate', 'customTags'],
|
||||
'gcp-sm': ['projectId', 'credentials', 'granularity', 'secretNameTemplate', 'customTags'],
|
||||
gh: ['accessToken', 'granularity', 'secretNameTemplate'],
|
||||
'vercel-project': [
|
||||
'accessToken',
|
||||
|
||||
Reference in New Issue
Block a user