Migrates secrets to prisma
This commit is contained in:
parent
a7fdedd310
commit
22da8d73d3
|
|
@ -24,6 +24,19 @@ model Audit {
|
||||||
response String?
|
response String?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model Secret {
|
||||||
|
versionId String @id
|
||||||
|
name String
|
||||||
|
description String?
|
||||||
|
secretString String
|
||||||
|
accountId String
|
||||||
|
region String
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
deletionDate DateTime?
|
||||||
|
|
||||||
|
@@index([name])
|
||||||
|
}
|
||||||
|
|
||||||
model SnsTopic {
|
model SnsTopic {
|
||||||
name String @id
|
name String @id
|
||||||
accountId String
|
accountId String
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
export interface CreateSecretDto {
|
|
||||||
versionId?: string;
|
|
||||||
name: string;
|
|
||||||
description?: string;
|
|
||||||
secretString?: string;
|
|
||||||
accountId: string;
|
|
||||||
region: string;
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { randomUUID } from 'crypto';
|
||||||
|
import * as Joi from 'joi';
|
||||||
|
|
||||||
import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler';
|
import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler';
|
||||||
import { Action } from '../action.enum';
|
import { Action } from '../action.enum';
|
||||||
import * as Joi from 'joi';
|
import { ArnUtil } from '../util/arn-util.static';
|
||||||
import { SecretService } from './secret.service';
|
import { SecretService } from './secret.service';
|
||||||
|
|
||||||
type QueryParams = {
|
type QueryParams = {
|
||||||
|
|
@ -22,7 +25,7 @@ export class CreateSecretHandler extends AbstractActionHandler<QueryParams> {
|
||||||
|
|
||||||
format = Format.Json;
|
format = Format.Json;
|
||||||
action = Action.SecretsManagerCreateSecret;
|
action = Action.SecretsManagerCreateSecret;
|
||||||
validator = Joi.object<QueryParams, true>({
|
validator = Joi.object<QueryParams, true>({
|
||||||
Name: Joi.string().required(),
|
Name: Joi.string().required(),
|
||||||
Description: Joi.string().allow('', null),
|
Description: Joi.string().allow('', null),
|
||||||
SecretString: Joi.string().allow('', null),
|
SecretString: Joi.string().allow('', null),
|
||||||
|
|
@ -34,7 +37,7 @@ export class CreateSecretHandler extends AbstractActionHandler<QueryParams> {
|
||||||
const { Name: name, Description: description, SecretString: secretString, ClientRequestToken } = params;
|
const { Name: name, Description: description, SecretString: secretString, ClientRequestToken } = params;
|
||||||
|
|
||||||
const secret = await this.secretService.create({
|
const secret = await this.secretService.create({
|
||||||
versionId: ClientRequestToken,
|
versionId: ClientRequestToken ?? randomUUID(),
|
||||||
description,
|
description,
|
||||||
name,
|
name,
|
||||||
secretString,
|
secretString,
|
||||||
|
|
@ -42,6 +45,8 @@ export class CreateSecretHandler extends AbstractActionHandler<QueryParams> {
|
||||||
region: awsProperties.region,
|
region: awsProperties.region,
|
||||||
});
|
});
|
||||||
|
|
||||||
return { ARN: secret.arn, VersionId: secret.versionId, Name: secret.name };
|
const arn = ArnUtil.fromSecret(secret);
|
||||||
|
|
||||||
|
return { ARN: arn, VersionId: secret.versionId, Name: secret.name };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||||
|
import * as Joi from 'joi';
|
||||||
|
|
||||||
|
import { PrismaService } from '../_prisma/prisma.service';
|
||||||
import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler';
|
import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler';
|
||||||
import { Action } from '../action.enum';
|
import { Action } from '../action.enum';
|
||||||
import * as Joi from 'joi';
|
import { ArnUtil } from '../util/arn-util.static';
|
||||||
import { Secret } from './secret.entity';
|
|
||||||
import { SecretService } from './secret.service';
|
import { SecretService } from './secret.service';
|
||||||
|
|
||||||
type QueryParams = {
|
type QueryParams = {
|
||||||
|
|
@ -12,24 +14,25 @@ type QueryParams = {
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DeleteSecretHandler extends AbstractActionHandler {
|
export class DeleteSecretHandler extends AbstractActionHandler {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly secretService: SecretService,
|
private readonly secretService: SecretService,
|
||||||
|
private readonly prismaService: PrismaService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
format = Format.Json;
|
format = Format.Json;
|
||||||
action = Action.SecretsManagerDeleteSecret;
|
action = Action.SecretsManagerDeleteSecret;
|
||||||
validator = Joi.object<QueryParams, true>({
|
validator = Joi.object<QueryParams, true>({
|
||||||
SecretId: Joi.string().required(),
|
SecretId: Joi.string().required(),
|
||||||
VersionId: Joi.string().allow(null, ''),
|
VersionId: Joi.string().allow(null, ''),
|
||||||
});
|
});
|
||||||
|
|
||||||
protected async handle({ SecretId, VersionId}: QueryParams, awsProperties: AwsProperties) {
|
protected async handle({ SecretId, VersionId }: QueryParams, awsProperties: AwsProperties) {
|
||||||
|
|
||||||
const name = Secret.getNameFromSecretId(SecretId);
|
const name = ArnUtil.getSecretNameFromSecretId(SecretId);
|
||||||
const secret = VersionId ?
|
const secret = VersionId ?
|
||||||
await this.secretService.findByNameAndVersion(name, VersionId) :
|
await this.secretService.findByNameAndVersion(name, VersionId) :
|
||||||
await this.secretService.findLatestByNameAndRegion(name, awsProperties.region);
|
await this.secretService.findLatestByNameAndRegion(name, awsProperties.region);
|
||||||
|
|
||||||
|
|
@ -37,10 +40,20 @@ export class DeleteSecretHandler extends AbstractActionHandler {
|
||||||
throw new BadRequestException('ResourceNotFoundException', "Secrets Manager can't find the resource that you asked for.");
|
throw new BadRequestException('ResourceNotFoundException', "Secrets Manager can't find the resource that you asked for.");
|
||||||
}
|
}
|
||||||
|
|
||||||
secret.deletionDate = new Date(Date.now() + 1000 * 60 * 60 * 24 * 5).toISOString();
|
await this.prismaService.secret.update({
|
||||||
await secret.save();
|
data: {
|
||||||
|
deletionDate: new Date(Date.now() + 1000 * 60 * 60 * 24 * 5),
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
versionId: secret.versionId,
|
||||||
|
name: secret.name,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const arn = ArnUtil.fromSecret(secret);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
Arn: secret.arn,
|
Arn: arn,
|
||||||
DeletionDate: secret.deletionDate,
|
DeletionDate: secret.deletionDate,
|
||||||
Name: secret.name,
|
Name: secret.name,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import * as Joi from 'joi';
|
||||||
import { Repository } from 'typeorm';
|
|
||||||
import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler';
|
import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler';
|
||||||
import { Action } from '../action.enum';
|
import { Action } from '../action.enum';
|
||||||
import * as Joi from 'joi';
|
|
||||||
import { Secret } from './secret.entity';
|
|
||||||
import { TagsService } from '../aws-shared-entities/tags.service';
|
import { TagsService } from '../aws-shared-entities/tags.service';
|
||||||
|
import { ArnUtil } from '../util/arn-util.static';
|
||||||
|
import { SecretService } from './secret.service';
|
||||||
|
|
||||||
type QueryParams = {
|
type QueryParams = {
|
||||||
SecretId: string;
|
SecretId: string;
|
||||||
|
|
@ -13,10 +13,9 @@ type QueryParams = {
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DescribeSecretHandler extends AbstractActionHandler {
|
export class DescribeSecretHandler extends AbstractActionHandler {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(Secret)
|
private readonly secretService: SecretService,
|
||||||
private readonly secretRepo: Repository<Secret>,
|
|
||||||
private readonly tagsService: TagsService,
|
private readonly tagsService: TagsService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
@ -28,20 +27,19 @@ export class DescribeSecretHandler extends AbstractActionHandler {
|
||||||
|
|
||||||
protected async handle({ SecretId }: QueryParams, awsProperties: AwsProperties) {
|
protected async handle({ SecretId }: QueryParams, awsProperties: AwsProperties) {
|
||||||
|
|
||||||
console.log({ SecretId })
|
const name = ArnUtil.getSecretNameFromSecretId(SecretId);
|
||||||
|
const secret = await this.secretService.findLatestByNameAndRegion(name, awsProperties.region);
|
||||||
const name = Secret.getNameFromSecretId(SecretId);
|
|
||||||
const secret = await this.secretRepo.findOne({ where: { name }, order: { createdAt: 'DESC' } });
|
|
||||||
|
|
||||||
if (!secret) {
|
if (!secret) {
|
||||||
throw new BadRequestException('ResourceNotFoundException', "Secrets Manager can't find the resource that you asked for.");
|
throw new BadRequestException('ResourceNotFoundException', "Secrets Manager can't find the resource that you asked for.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const tags = await this.tagsService.getByArn(secret.arn);
|
const arn = ArnUtil.fromSecret(secret);
|
||||||
|
const tags = await this.tagsService.getByArn(arn);
|
||||||
const listOfTagPairs = TagsService.getJsonSafeTagsMap(tags);
|
const listOfTagPairs = TagsService.getJsonSafeTagsMap(tags);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"ARN": secret.arn,
|
"ARN": arn,
|
||||||
"CreatedDate": new Date(secret.createdAt).toISOString(),
|
"CreatedDate": new Date(secret.createdAt).toISOString(),
|
||||||
"DeletedDate": secret.deletionDate ? new Date(secret.deletionDate).toISOString() : null,
|
"DeletedDate": secret.deletionDate ? new Date(secret.deletionDate).toISOString() : null,
|
||||||
"Description": secret.description,
|
"Description": secret.description,
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import * as Joi from 'joi';
|
||||||
import { Repository } from 'typeorm';
|
|
||||||
import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler';
|
import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler';
|
||||||
import { Action } from '../action.enum';
|
import { Action } from '../action.enum';
|
||||||
import * as Joi from 'joi';
|
|
||||||
import { Secret } from './secret.entity';
|
|
||||||
import { AttributesService } from '../aws-shared-entities/attributes.service';
|
import { AttributesService } from '../aws-shared-entities/attributes.service';
|
||||||
|
import { ArnUtil } from '../util/arn-util.static';
|
||||||
|
import { SecretService } from './secret.service';
|
||||||
|
|
||||||
type QueryParams = {
|
type QueryParams = {
|
||||||
SecretId: string;
|
SecretId: string;
|
||||||
|
|
@ -15,8 +15,7 @@ type QueryParams = {
|
||||||
export class GetResourcePolicyHandler extends AbstractActionHandler {
|
export class GetResourcePolicyHandler extends AbstractActionHandler {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(Secret)
|
private readonly secretService: SecretService,
|
||||||
private readonly secretRepo: Repository<Secret>,
|
|
||||||
private readonly attributesService: AttributesService,
|
private readonly attributesService: AttributesService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
@ -28,16 +27,17 @@ export class GetResourcePolicyHandler extends AbstractActionHandler {
|
||||||
|
|
||||||
protected async handle({ SecretId }: QueryParams, awsProperties: AwsProperties) {
|
protected async handle({ SecretId }: QueryParams, awsProperties: AwsProperties) {
|
||||||
|
|
||||||
const name = Secret.getNameFromSecretId(SecretId);
|
const name = ArnUtil.getSecretNameFromSecretId(SecretId);
|
||||||
const secret = await this.secretRepo.findOne({ where: { name }, order: { createdAt: 'DESC' } });
|
const secret = await this.secretService.findLatestByNameAndRegion(name, awsProperties.region);
|
||||||
|
|
||||||
if (!secret) {
|
if (!secret) {
|
||||||
throw new BadRequestException('ResourceNotFoundException', "Secrets Manager can't find the resource that you asked for.");
|
throw new BadRequestException('ResourceNotFoundException', "Secrets Manager can't find the resource that you asked for.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const attribute = await this.attributesService.getResourcePolicyByArn(secret.arn);
|
const arn = ArnUtil.fromSecret(secret);
|
||||||
|
const attribute = await this.attributesService.getResourcePolicyByArn(arn);
|
||||||
return {
|
return {
|
||||||
ARN: secret.arn,
|
ARN: arn,
|
||||||
Name: secret.name,
|
Name: secret.name,
|
||||||
ResourcePolicy: attribute?.value,
|
ResourcePolicy: attribute?.value,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||||
|
import * as Joi from 'joi';
|
||||||
|
|
||||||
import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler';
|
import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler';
|
||||||
import { Action } from '../action.enum';
|
import { Action } from '../action.enum';
|
||||||
import * as Joi from 'joi';
|
import { ArnUtil } from '../util/arn-util.static';
|
||||||
import { Secret } from './secret.entity';
|
|
||||||
import { SecretService } from './secret.service';
|
import { SecretService } from './secret.service';
|
||||||
|
|
||||||
type QueryParams = {
|
type QueryParams = {
|
||||||
|
|
@ -28,7 +29,7 @@ export class GetSecretValueHandler extends AbstractActionHandler {
|
||||||
|
|
||||||
protected async handle({ SecretId, VersionId}: QueryParams, awsProperties: AwsProperties) {
|
protected async handle({ SecretId, VersionId}: QueryParams, awsProperties: AwsProperties) {
|
||||||
|
|
||||||
const name = Secret.getNameFromSecretId(SecretId);
|
const name = ArnUtil.getSecretNameFromSecretId(SecretId);
|
||||||
const secret = VersionId ?
|
const secret = VersionId ?
|
||||||
await this.secretService.findByNameAndVersion(name, VersionId) :
|
await this.secretService.findByNameAndVersion(name, VersionId) :
|
||||||
await this.secretService.findLatestByNameAndRegion(name, awsProperties.region);
|
await this.secretService.findLatestByNameAndRegion(name, awsProperties.region);
|
||||||
|
|
@ -37,8 +38,10 @@ export class GetSecretValueHandler extends AbstractActionHandler {
|
||||||
throw new BadRequestException('ResourceNotFoundException', "Secrets Manager can't find the resource that you asked for.");
|
throw new BadRequestException('ResourceNotFoundException', "Secrets Manager can't find the resource that you asked for.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const arn = ArnUtil.fromSecret(secret);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ARN: secret.arn,
|
ARN: arn,
|
||||||
CreatedDate: new Date(secret.createdAt).valueOf() / 1000,
|
CreatedDate: new Date(secret.createdAt).valueOf() / 1000,
|
||||||
Name: secret.name,
|
Name: secret.name,
|
||||||
SecretString: secret.secretString,
|
SecretString: secret.secretString,
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import * as Joi from 'joi';
|
||||||
import { Repository } from 'typeorm';
|
|
||||||
import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler';
|
import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler';
|
||||||
import { Action } from '../action.enum';
|
import { Action } from '../action.enum';
|
||||||
import * as Joi from 'joi';
|
|
||||||
import { Secret } from './secret.entity';
|
|
||||||
import { AttributesService } from '../aws-shared-entities/attributes.service';
|
import { AttributesService } from '../aws-shared-entities/attributes.service';
|
||||||
|
import { ArnUtil } from '../util/arn-util.static';
|
||||||
|
import { SecretService } from './secret.service';
|
||||||
|
|
||||||
type QueryParams = {
|
type QueryParams = {
|
||||||
SecretId: string;
|
SecretId: string;
|
||||||
|
|
@ -16,8 +16,7 @@ type QueryParams = {
|
||||||
export class PutResourcePolicyHandler extends AbstractActionHandler {
|
export class PutResourcePolicyHandler extends AbstractActionHandler {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(Secret)
|
private readonly secretService: SecretService,
|
||||||
private readonly secretRepo: Repository<Secret>,
|
|
||||||
private readonly attributesService: AttributesService,
|
private readonly attributesService: AttributesService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
|
@ -32,16 +31,17 @@ export class PutResourcePolicyHandler extends AbstractActionHandler {
|
||||||
|
|
||||||
protected async handle({ SecretId, ResourcePolicy }: QueryParams, awsProperties: AwsProperties) {
|
protected async handle({ SecretId, ResourcePolicy }: QueryParams, awsProperties: AwsProperties) {
|
||||||
|
|
||||||
const name = Secret.getNameFromSecretId(SecretId);
|
const name = ArnUtil.getSecretNameFromSecretId(SecretId);
|
||||||
const secret = await this.secretRepo.findOne({ where: { name }, order: { createdAt: 'DESC' } });
|
const secret = await this.secretService.findLatestByNameAndRegion(name, awsProperties.region);
|
||||||
|
|
||||||
if (!secret) {
|
if (!secret) {
|
||||||
throw new BadRequestException('ResourceNotFoundException', "Secrets Manager can't find the resource that you asked for.");
|
throw new BadRequestException('ResourceNotFoundException', "Secrets Manager can't find the resource that you asked for.");
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.attributesService.createResourcePolicy(secret.arn, ResourcePolicy);
|
const arn = ArnUtil.fromSecret(secret);
|
||||||
|
await this.attributesService.createResourcePolicy(arn, ResourcePolicy);
|
||||||
return {
|
return {
|
||||||
ARN: secret.arn,
|
ARN: arn,
|
||||||
Name: secret.name,
|
Name: secret.name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||||
|
import { randomUUID } from 'crypto';
|
||||||
|
import * as Joi from 'joi';
|
||||||
|
|
||||||
import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler';
|
import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler';
|
||||||
import { Action } from '../action.enum';
|
import { Action } from '../action.enum';
|
||||||
import * as Joi from 'joi';
|
import { ArnUtil } from '../util/arn-util.static';
|
||||||
import { Secret } from './secret.entity';
|
|
||||||
import { SecretService } from './secret.service';
|
import { SecretService } from './secret.service';
|
||||||
|
|
||||||
type QueryParams = {
|
type QueryParams = {
|
||||||
|
|
@ -31,7 +33,7 @@ export class PutSecretValueHandler extends AbstractActionHandler<QueryParams> {
|
||||||
protected async handle(params: QueryParams, awsProperties: AwsProperties) {
|
protected async handle(params: QueryParams, awsProperties: AwsProperties) {
|
||||||
|
|
||||||
const { SecretId, SecretString: secretString, ClientRequestToken } = params;
|
const { SecretId, SecretString: secretString, ClientRequestToken } = params;
|
||||||
const name = Secret.getNameFromSecretId(SecretId);
|
const name = ArnUtil.getSecretNameFromSecretId(SecretId);
|
||||||
const oldSecret = await this.secretService.findLatestByNameAndRegion(name, awsProperties.region);
|
const oldSecret = await this.secretService.findLatestByNameAndRegion(name, awsProperties.region);
|
||||||
|
|
||||||
if (!oldSecret) {
|
if (!oldSecret) {
|
||||||
|
|
@ -39,13 +41,15 @@ export class PutSecretValueHandler extends AbstractActionHandler<QueryParams> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const secret = await this.secretService.create({
|
const secret = await this.secretService.create({
|
||||||
versionId: ClientRequestToken,
|
versionId: ClientRequestToken ?? randomUUID(),
|
||||||
name: oldSecret.name,
|
name: oldSecret.name,
|
||||||
secretString,
|
secretString,
|
||||||
accountId: awsProperties.accountId,
|
accountId: awsProperties.accountId,
|
||||||
region: awsProperties.region,
|
region: awsProperties.region,
|
||||||
});
|
});
|
||||||
|
|
||||||
return { ARN: secret.arn, VersionId: secret.versionId, Name: secret.name, VersionStages: [] }
|
const arn = ArnUtil.fromSecret(secret);
|
||||||
|
|
||||||
|
return { ARN: arn, VersionId: secret.versionId, Name: secret.name, VersionStages: [] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
import { BaseEntity, Column, CreateDateColumn, Entity, Index, PrimaryColumn, PrimaryGeneratedColumn } from 'typeorm';
|
|
||||||
|
|
||||||
@Entity('secret')
|
|
||||||
export class Secret extends BaseEntity {
|
|
||||||
|
|
||||||
@PrimaryColumn({ name: 'versionId' })
|
|
||||||
versionId: string;
|
|
||||||
|
|
||||||
@Column({ name: 'name', nullable: false })
|
|
||||||
@Index()
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
@Column({ name: 'description', nullable: true })
|
|
||||||
description: string;
|
|
||||||
|
|
||||||
@Column({ name: 'secret_string', nullable: true })
|
|
||||||
secretString: string;
|
|
||||||
|
|
||||||
@Column({ name: 'account_id', nullable: false })
|
|
||||||
accountId: string;
|
|
||||||
|
|
||||||
@Column({ name: 'region', nullable: false })
|
|
||||||
region: string;
|
|
||||||
|
|
||||||
@CreateDateColumn()
|
|
||||||
createdAt: string;
|
|
||||||
|
|
||||||
@Column({ name: 'deletion_date', nullable: true })
|
|
||||||
deletionDate: string;
|
|
||||||
|
|
||||||
get arn(): string {
|
|
||||||
return `arn:aws:secretsmanager:${this.region}:${this.accountId}:${this.name}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static getNameFromSecretId(secretId: string) {
|
|
||||||
const parts = secretId.split(':');
|
|
||||||
return parts.length > 1 ? parts.pop() : secretId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,32 +1,30 @@
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { Prisma, Secret } from '@prisma/client';
|
||||||
import { Repository } from 'typeorm';
|
import { randomUUID } from 'crypto';
|
||||||
import { CreateSecretDto } from './create-secret.dto';
|
|
||||||
import { Secret } from './secret.entity';
|
import { PrismaService } from '../_prisma/prisma.service';
|
||||||
import * as uuid from 'uuid';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SecretService {
|
export class SecretService {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(Secret)
|
private readonly prismaService: PrismaService,
|
||||||
private readonly secretRepo: Repository<Secret>,
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async findLatestByNameAndRegion(name: string, region: string): Promise<Secret> {
|
async findLatestByNameAndRegion(name: string, region: string): Promise<Secret | null> {
|
||||||
return await this.secretRepo.findOne({ where: { name, region }, order: { createdAt: 'DESC' } });
|
return await this.prismaService.secret.findFirst({ where: { name, region }, orderBy: { createdAt: 'desc' } });
|
||||||
}
|
}
|
||||||
|
|
||||||
async findByNameAndVersion(name: string, versionId: string): Promise<Secret> {
|
async findByNameAndVersion(name: string, versionId: string): Promise<Secret | null> {
|
||||||
// TypeORM BUG: https://github.com/typeorm/typeorm/issues/5694 - Cannot use findOne here
|
return await this.prismaService.secret.findFirst({ where: { name, versionId } });
|
||||||
const [ secret ] = await this.secretRepo.find({ where: { name, versionId } });
|
|
||||||
return secret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(dto: CreateSecretDto): Promise<Secret> {
|
async create(data: Prisma.SecretCreateInput): Promise<Secret> {
|
||||||
return await this.secretRepo.create({
|
return await this.prismaService.secret.create({
|
||||||
...dto,
|
data: {
|
||||||
versionId: dto.versionId ?? uuid.v4(),
|
...data,
|
||||||
}).save();
|
versionId: data.versionId ?? randomUUID(),
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
|
||||||
|
import { PrismaModule } from '../_prisma/prisma.module';
|
||||||
import { Format } from '../abstract-action.handler';
|
import { Format } from '../abstract-action.handler';
|
||||||
import { Action } from '../action.enum';
|
import { Action } from '../action.enum';
|
||||||
import { AwsSharedEntitiesModule } from '../aws-shared-entities/aws-shared-entities.module';
|
import { AwsSharedEntitiesModule } from '../aws-shared-entities/aws-shared-entities.module';
|
||||||
|
|
@ -12,7 +13,6 @@ import { GetResourcePolicyHandler } from './get-resource-policy.handler';
|
||||||
import { GetSecretValueHandler } from './get-secret-value.handler';
|
import { GetSecretValueHandler } from './get-secret-value.handler';
|
||||||
import { PutResourcePolicyHandler } from './put-resource-policy.handler';
|
import { PutResourcePolicyHandler } from './put-resource-policy.handler';
|
||||||
import { PutSecretValueHandler } from './put-secret-value.handler';
|
import { PutSecretValueHandler } from './put-secret-value.handler';
|
||||||
import { Secret } from './secret.entity';
|
|
||||||
import { SecretService } from './secret.service';
|
import { SecretService } from './secret.service';
|
||||||
import { SecretsManagerHandlers } from './secrets-manager.constants';
|
import { SecretsManagerHandlers } from './secrets-manager.constants';
|
||||||
|
|
||||||
|
|
@ -53,7 +53,7 @@ const actions = [
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
TypeOrmModule.forFeature([Secret]),
|
PrismaModule,
|
||||||
AwsSharedEntitiesModule,
|
AwsSharedEntitiesModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { SnsTopic, SnsTopicSubscription } from "@prisma/client";
|
import { Secret, SnsTopic, SnsTopicSubscription } from "@prisma/client";
|
||||||
|
|
||||||
export class ArnUtil {
|
export class ArnUtil {
|
||||||
|
|
||||||
|
|
@ -9,4 +9,13 @@ export class ArnUtil {
|
||||||
static fromTopicSub(topicSub: SnsTopicSubscription): string {
|
static fromTopicSub(topicSub: SnsTopicSubscription): string {
|
||||||
return `${topicSub.topicArn}:${topicSub.id}`;
|
return `${topicSub.topicArn}:${topicSub.id}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static fromSecret(secret: Secret): string {
|
||||||
|
return `arn:aws:secretsmanager:${secret.region}:${secret.accountId}:${secret.name}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getSecretNameFromSecretId(secretId: string): string {
|
||||||
|
const parts = secretId.split(':');
|
||||||
|
return parts.length > 1 ? parts.pop() as string : secretId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue