Skip to content

Commit

Permalink
Add GCP secret engine configuration Create/Edit views (#29423)
Browse files Browse the repository at this point in the history
* gcp initial changes

* acceptance test coverage for gcp

* update config-wif component test so tests are passing

* specific gcp test coverage

* changelog

* comment clean up

* one more test

* comment things

* address pr comments
  • Loading branch information
Monkeychip authored Jan 30, 2025
1 parent 9c0f2fb commit 14082d0
Show file tree
Hide file tree
Showing 14 changed files with 464 additions and 138 deletions.
6 changes: 6 additions & 0 deletions changelog/29423.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
```release-note:improvement
ui: Adds ability to edit, create, and view the GCP secrets engine configuration.
```
```release-note:improvement
ui (enterprise): Allow WIF configuration on the GCP secrets engine.
```
20 changes: 20 additions & 0 deletions ui/app/adapters/gcp/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,24 @@ export default class GcpConfig extends ApplicationAdapter {
};
});
}

createOrUpdate(store, type, snapshot) {
const serializer = store.serializerFor(type.modelName);
const data = serializer.serialize(snapshot);
const backend = snapshot.record.backend;
return this.ajax(this._url(backend), 'POST', { data }).then((resp) => {
return {
...resp,
id: backend,
};
});
}

createRecord() {
return this.createOrUpdate(...arguments);
}

updateRecord() {
return this.createOrUpdate(...arguments);
}
}
17 changes: 7 additions & 10 deletions ui/app/components/secret-engine/configuration-details.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,12 @@
@title="{{@typeDisplay}} not configured"
@message="Get started by configuring your {{@typeDisplay}} secrets engine."
>
{{! TODO: short-term conditional to be removed once configuration for gcp is merged. }}
{{#unless (eq @typeDisplay "Google Cloud")}}
<Hds::Link::Standalone
@icon="chevron-right"
@iconPosition="trailing"
@text="Configure {{@typeDisplay}}"
@route="vault.cluster.secrets.backend.configuration.edit"
@model={{@id}}
/>
{{/unless}}
<Hds::Link::Standalone
@icon="chevron-right"
@iconPosition="trailing"
@text="Configure {{@typeDisplay}}"
@route="vault.cluster.secrets.backend.configuration.edit"
@model={{@id}}
/>
</EmptyState>
{{/each}}
2 changes: 1 addition & 1 deletion ui/app/helpers/mountable-secret-engines.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ const MOUNTABLE_SECRET_ENGINES = [
];

// A list of Workload Identity Federation engines.
export const WIF_ENGINES = ['aws', 'azure'];
export const WIF_ENGINES = ['aws', 'azure', 'gcp'];

export function wifEngines() {
return WIF_ENGINES.slice();
Expand Down
79 changes: 59 additions & 20 deletions ui/app/models/gcp/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,12 @@
*/

import Model, { attr } from '@ember-data/model';
import { expandAttributeMeta } from 'vault/utils/field-to-attrs';
import fieldToAttrs, { expandAttributeMeta } from 'vault/utils/field-to-attrs';

export default class GcpConfig extends Model {
@attr('string') backend; // dynamic path of secret -- set on response from value passed to queryRecord

/* GCP config fields */
@attr({
label: 'Config TTL',
editType: 'ttl',
helperTextDisabled: 'The TTL (time-to-live) of generated tokens.',
})
ttl;

@attr({
label: 'Max TTL',
editType: 'ttl',
helperTextDisabled:
'Specifies the maximum config TTL (time-to-live) for long-lived credentials (i.e. service account keys).',
})
maxTtl;

/* GCP credential config field */
// GCP only field
@attr('string', {
label: 'JSON credentials',
subText:
Expand All @@ -35,7 +19,7 @@ export default class GcpConfig extends Model {
})
credentials; // obfuscated, never returned by API.

/* WIF config fields */
// WIF only fields
@attr('string', {
subText:
'The audience claim value for plugin identity tokens. Must match an allowed audience configured for the target IAM OIDC identity provider.',
Expand All @@ -45,7 +29,7 @@ export default class GcpConfig extends Model {
@attr({
label: 'Identity token TTL',
helperTextDisabled:
'The TTL of generated tokens. Defaults to 1 hour, toggle on to specify a different value.',
'The TTL of generated tokens. Defaults to 1 hour, turn on the toggle to specify a different value.',
helperTextEnabled: 'The TTL of generated tokens.',
editType: 'ttl',
})
Expand All @@ -56,6 +40,26 @@ export default class GcpConfig extends Model {
})
serviceAccountEmail;

// Fields that show regardless of access type
@attr({
label: 'Config TTL',
editType: 'ttl',
helperTextDisabled: 'Vault will use the default config TTL (time-to-live) for long-lived credentials.',
helperTextEnabled:
'The default config TTL (time-to-live) for long-lived credentials (i.e. service account keys).',
})
ttl;

@attr({
label: 'Max TTL',
editType: 'ttl',
helperTextDisabled:
'Vault will use the default maximum config TTL (time-to-live) for long-lived credentials.',
helperTextEnabled:
'The maximum config TTL (time-to-live) for long-lived credentials (i.e. service account keys).',
})
maxTtl;

configurableParams = [
'credentials',
'serviceAccountEmail',
Expand All @@ -65,8 +69,43 @@ export default class GcpConfig extends Model {
'identityTokenTtl',
];

get isWifPluginConfigured() {
return !!this.identityTokenAudience || !!this.identityTokenTtl || !!this.serviceAccountEmail;
}

isAccountPluginConfigured = false;
// the "credentials" param is not checked for "isAccountPluginConfigured" because it's never return by the API
// additionally credentials can be set via GOOGLE_APPLICATION_CREDENTIALS env var so we cannot call it a required field in the ui.
// thus we can never say for sure if the account accessType has been configured so we always return false

get displayAttrs() {
const formFields = expandAttributeMeta(this, this.configurableParams);
return formFields.filter((attr) => attr.name !== 'credentials');
}

get fieldGroupsWif() {
return fieldToAttrs(this, this.formFieldGroups('wif'));
}

get fieldGroupsAccount() {
return fieldToAttrs(this, this.formFieldGroups('account'));
}

formFieldGroups(accessType = 'account') {
const formFieldGroups = [];
if (accessType === 'wif') {
formFieldGroups.push({
default: ['identityTokenAudience', 'serviceAccountEmail', 'identityTokenTtl'],
});
}
if (accessType === 'account') {
formFieldGroups.push({
default: ['credentials'],
});
}
formFieldGroups.push({
'More options': ['ttl', 'maxTtl'],
});
return formFieldGroups;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import type VersionService from 'vault/services/version';
const MOUNT_CONFIG_MODEL_NAMES: Record<string, string[]> = {
aws: ['aws/root-config', 'aws/lease-config'],
azure: ['azure/config'],
gcp: ['gcp/config'],
ssh: ['ssh/ca-config'],
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,17 @@
<SecretListHeader @model={{this.model.secretEngineModel}} @isConfigure={{true}} />

{{#if this.isConfigurable}}
{{! TODO: short-term conditional to be removed once configuration for gcp is merged. }}
{{#unless (eq this.typeDisplay "Google Cloud")}}
<Toolbar>
<ToolbarActions>
<ToolbarLink
@route="vault.cluster.secrets.backend.configuration.edit"
@model={{this.model.secretEngineModel.id}}
data-test-secret-backend-configure
>
Configure
</ToolbarLink>
</ToolbarActions>
</Toolbar>
{{/unless}}
<Toolbar>
<ToolbarActions>
<ToolbarLink
@route="vault.cluster.secrets.backend.configuration.edit"
@model={{this.model.secretEngineModel.id}}
data-test-secret-backend-configure
>
Configure
</ToolbarLink>
</ToolbarActions>
</Toolbar>

<SecretEngine::ConfigurationDetails
@configModels={{this.model.configModels}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ module('Acceptance | aws | configuration', function (hooks) {
return authPage.login();
});

module('isEnterprise', function (hooks) {
module('Enterprise', function (hooks) {
hooks.beforeEach(function () {
this.version.type = 'enterprise';
});
Expand Down Expand Up @@ -338,7 +338,7 @@ module('Acceptance | aws | configuration', function (hooks) {
});
});

module('isCommunity', function (hooks) {
module('Community', function (hooks) {
hooks.beforeEach(function () {
this.version.type = 'community';
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ module('Acceptance | Azure | configuration', function (hooks) {
await runCmd(`delete sys/mounts/${path}`);
});

module('isCommunity', function (hooks) {
module('Community', function (hooks) {
hooks.beforeEach(function () {
this.version.type = 'community';
});
Expand Down Expand Up @@ -252,7 +252,7 @@ module('Acceptance | Azure | configuration', function (hooks) {
});
});

module('isEnterprise', function (hooks) {
module('Enterprise', function (hooks) {
hooks.beforeEach(function () {
this.version.type = 'enterprise';
});
Expand Down
Loading

0 comments on commit 14082d0

Please sign in to comment.