Add requested improvements to vault plugin
Signed-off-by: ivgo <ivgo@spreadgroup.com>
This commit is contained in:
@@ -45,9 +45,6 @@ export type VaultBuilderReturn = {
|
||||
* @public
|
||||
*/
|
||||
export class VaultBuilder {
|
||||
// private vaultTokenRefreshInterval: Duration = Duration.fromObject({
|
||||
// minutes: 60,
|
||||
// });
|
||||
private vaultClient?: VaultClient;
|
||||
|
||||
/**
|
||||
@@ -118,26 +115,12 @@ export class VaultBuilder {
|
||||
fn: async () => {
|
||||
this.env.logger.info('Renewing Vault token');
|
||||
const vaultClient = this.vaultClient ?? new VaultClient(this.env);
|
||||
await this.renewToken(vaultClient);
|
||||
await vaultClient.renewToken();
|
||||
},
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renews the token for vault using a defined client.
|
||||
*
|
||||
* @param vaultClient - The vault client used to renew the token
|
||||
*/
|
||||
protected async renewToken(vaultClient: VaultClient) {
|
||||
const result = await vaultClient.renewToken();
|
||||
if (!result) {
|
||||
this.env.logger.warn('Error renewing vault token');
|
||||
} else {
|
||||
this.env.logger.info('Vault token renewed');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the backend routes for Vault.
|
||||
*
|
||||
@@ -159,7 +142,7 @@ export class VaultBuilder {
|
||||
}
|
||||
|
||||
const secrets = await vaultClient.listSecrets(path);
|
||||
res.json(secrets);
|
||||
res.json({ items: secrets });
|
||||
});
|
||||
|
||||
return router;
|
||||
|
||||
@@ -93,8 +93,7 @@ describe('VaultApi', () => {
|
||||
it('should return success token renew', async () => {
|
||||
setupHandlers();
|
||||
const api = new VaultClient({ config });
|
||||
const apiRenew = await api.renewToken();
|
||||
expect(apiRenew).toBeTruthy();
|
||||
expect(await api.renewToken()).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should render frontend url', () => {
|
||||
|
||||
@@ -15,12 +15,13 @@
|
||||
*/
|
||||
|
||||
import { Config } from '@backstage/config';
|
||||
import { NotFoundError } from '@backstage/errors';
|
||||
import fetch from 'cross-fetch';
|
||||
import { getVaultConfig, VaultConfig } from '../config';
|
||||
|
||||
/**
|
||||
* Object received as a response from the Vault API when fetching secrets
|
||||
* @public
|
||||
* @internal
|
||||
*/
|
||||
export type VaultSecretList = {
|
||||
data: {
|
||||
@@ -40,9 +41,8 @@ export type VaultSecret = {
|
||||
|
||||
/**
|
||||
* Object received as response when the token is renewed using the Vault API
|
||||
* @public
|
||||
*/
|
||||
export type RenewTokenResponse = {
|
||||
type RenewTokenResponse = {
|
||||
auth: {
|
||||
client_token: string;
|
||||
};
|
||||
@@ -63,10 +63,10 @@ export interface VaultApi {
|
||||
*/
|
||||
listSecrets(secretPath: string): Promise<VaultSecret[]>;
|
||||
/**
|
||||
* Optional, to renew the token used to list the secrets. Returns true
|
||||
* if the action was successfull, false otherwise.
|
||||
* Optional, to renew the token used to list the secrets. Throws an
|
||||
* error if the token renewal went wrong.
|
||||
*/
|
||||
renewToken?(): Promise<boolean>;
|
||||
renewToken?(): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,7 +84,7 @@ export class VaultClient implements VaultApi {
|
||||
path: string,
|
||||
query: { [key in string]: any },
|
||||
method: string = 'GET',
|
||||
): Promise<T | undefined> {
|
||||
): Promise<T> {
|
||||
const url = new URL(path, this.vaultConfig.baseUrl);
|
||||
const response = await fetch(
|
||||
`${url.toString()}?${new URLSearchParams(query).toString()}`,
|
||||
@@ -96,15 +96,14 @@ export class VaultClient implements VaultApi {
|
||||
},
|
||||
},
|
||||
);
|
||||
if (response.status === 200) {
|
||||
if (response.ok) {
|
||||
return (await response.json()) as T;
|
||||
} else if (response.status === 404) {
|
||||
throw new NotFoundError(`No secrets found in path '${path}'`);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private isFolder(secretName: string): boolean {
|
||||
const regex = /^.*\/$/gm;
|
||||
return regex.test(secretName);
|
||||
throw new Error(
|
||||
`Unexpected error while fetching secrets from path '${path}'`,
|
||||
);
|
||||
}
|
||||
|
||||
getFrontendSecretsUrl(): string {
|
||||
@@ -117,14 +116,11 @@ export class VaultClient implements VaultApi {
|
||||
? `v1/${this.vaultConfig.secretEngine}/metadata/${secretPath}`
|
||||
: `v1/${this.vaultConfig.secretEngine}/${secretPath}`;
|
||||
const result = await this.callApi<VaultSecretList>(listUrl, { list: true });
|
||||
if (!result) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const secrets: VaultSecret[] = [];
|
||||
await Promise.all(
|
||||
result.data.keys.map(async secret => {
|
||||
if (this.isFolder(secret)) {
|
||||
if (secret.endsWith('/')) {
|
||||
secrets.push(
|
||||
...(await this.listSecrets(`${secretPath}/${secret.slice(0, -1)}`)),
|
||||
);
|
||||
@@ -141,17 +137,13 @@ export class VaultClient implements VaultApi {
|
||||
return secrets;
|
||||
}
|
||||
|
||||
async renewToken(): Promise<boolean> {
|
||||
async renewToken(): Promise<void> {
|
||||
const result = await this.callApi<RenewTokenResponse>(
|
||||
'v1/auth/token/renew-self',
|
||||
{},
|
||||
'POST',
|
||||
);
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.vaultConfig.token = result.auth.client_token;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user