diff --git a/prisma/local-aws-state.sqlite b/prisma/local-aws-state.sqlite deleted file mode 100644 index 20eae5d..0000000 Binary files a/prisma/local-aws-state.sqlite and /dev/null differ diff --git a/prisma/schema.prisma b/prisma/schema.prisma index d45cfa9..0d57aa4 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -24,6 +24,39 @@ model Audit { response String? } +model IamRole { + id String @id + path String? + name String + assumeRolePolicy String? + description String? + maxSessionDuration Int? + permissionBoundaryArn String? + lastUsedDate DateTime? + lastUsedRegion String? + accountId String + createdAt DateTime @default(now()) + + @@unique([accountId, name]) +} + +model IamPolicy { + id String + version Int @default(1) + isDefault Boolean + path String? + name String + description String? + policy String + isAttachable Boolean @default(false) + accountId String + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + @@id([id, version]) + @@unique([accountId, path, name]) +} + model KmsAlias { name String accountId String diff --git a/src/app.module.ts b/src/app.module.ts index 827e5b2..8586476 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -17,6 +17,8 @@ import { SqsModule } from './sqs/sqs.module'; import { PrismaModule } from './_prisma/prisma.module'; import { StsModule } from './sts/sts.module'; import { StsHandlers } from './sts/sts.constants'; +import { IamModule } from './iam/iam.module'; +import { IAMHandlers } from './iam/iam.constants'; @Module({ imports: [ @@ -26,6 +28,7 @@ import { StsHandlers } from './sts/sts.constants'; }), PrismaModule, AwsSharedEntitiesModule, + IamModule, KmsModule, SecretsManagerModule, SnsModule, @@ -41,6 +44,7 @@ import { StsHandlers } from './sts/sts.constants'; provide: ActionHandlers, useFactory: (...args) => args.reduce((m, hs) => ({ ...m, ...hs }), {}), inject: [ + IAMHandlers, KMSHandlers, SecretsManagerHandlers, SnsHandlers, diff --git a/src/aws-shared-entities/aws-exceptions.ts b/src/aws-shared-entities/aws-exceptions.ts index 94bee64..32886d1 100644 --- a/src/aws-shared-entities/aws-exceptions.ts +++ b/src/aws-shared-entities/aws-exceptions.ts @@ -162,4 +162,13 @@ export class UnsupportedOperationException extends AwsException { HttpStatus.BAD_REQUEST, ) } -} \ No newline at end of file +} +export class EntityAlreadyExists extends AwsException { + constructor(message: string) { + super( + message, + EntityAlreadyExists.name, + HttpStatus.CONFLICT, + ) + } +} diff --git a/src/iam/attach-role-policy.handler.ts b/src/iam/attach-role-policy.handler.ts new file mode 100644 index 0000000..2809aa2 --- /dev/null +++ b/src/iam/attach-role-policy.handler.ts @@ -0,0 +1,31 @@ +import { Injectable } from '@nestjs/common'; +import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler'; +import { Action } from '../action.enum'; +import * as Joi from 'joi'; + +type QueryParams = { + PolicyArn: string; + RoleName: string; +} + +@Injectable() +export class AttachRolePolicyHandler extends AbstractActionHandler { + + constructor( + + ) { + super(); + } + + format = Format.Xml; + action = Action.IamAttachRolePolicy; + validator = Joi.object({ + PolicyArn: Joi.string().required(), + RoleName: Joi.string().required(), + }); + + protected async handle({ PolicyArn, RoleName }: QueryParams, awsProperties: AwsProperties) { + + + } +} diff --git a/src/iam/create-policy-version.handler.ts b/src/iam/create-policy-version.handler.ts new file mode 100644 index 0000000..a649897 --- /dev/null +++ b/src/iam/create-policy-version.handler.ts @@ -0,0 +1,35 @@ +import { Injectable } from '@nestjs/common'; +import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler'; +import { Action } from '../action.enum'; +import * as Joi from 'joi'; +import { IamPolicy } from './iam-policy.entity'; +import { breakdownArn } from '../util/breakdown-arn'; + +type QueryParams = { + PolicyArn: string; + PolicyDocument: string; + SetAsDefault: boolean; +} + +@Injectable() +export class CreatePolicyVersionHandler extends AbstractActionHandler { + + constructor( + ) { + super(); + } + + format = Format.Xml; + action = Action.IamCreatePolicyVersion; + validator = Joi.object({ + PolicyArn: Joi.string().required(), + PolicyDocument: Joi.string().required(), + SetAsDefault: Joi.boolean().required(), + }); + + protected async handle({ PolicyArn, PolicyDocument, SetAsDefault }: QueryParams, awsProperties: AwsProperties) { + + + + } +} diff --git a/src/iam/create-policy.handler.ts b/src/iam/create-policy.handler.ts new file mode 100644 index 0000000..a472749 --- /dev/null +++ b/src/iam/create-policy.handler.ts @@ -0,0 +1,53 @@ +import { Injectable } from '@nestjs/common'; +import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler'; +import { Action } from '../action.enum'; +import * as Joi from 'joi'; +import { IamPolicy } from './iam-policy.entity'; +import { IamService } from './iam.service'; +import { TagsService } from '../aws-shared-entities/tags.service'; +import { randomUUID } from 'crypto'; + +type QueryParams = { + Description: string; + Path: string; + PolicyDocument: string; + PolicyName: string; +} & Record; + +@Injectable() +export class CreatePolicyHandler extends AbstractActionHandler { + + constructor( + private readonly iamService: IamService, + private readonly tagsService: TagsService, + ) { + super(); + } + + format = Format.Xml; + action = Action.IamCreatePolicy; + validator = Joi.object({ + Description: Joi.string().max(1000).allow(null, '').default(null), + Path: Joi.string().min(1).max(512).default(null).regex(new RegExp(`((/[A-Za-z0-9\.,\+@=_-]+)*)/`)), + PolicyDocument: Joi.string().min(1).max(131072).required(), + PolicyName: Joi.string().min(1).max(128).required(), + }); + + protected async handle(params: QueryParams, awsProperties: AwsProperties) { + + const { Description, Path, PolicyName, PolicyDocument } = params; + + const policy = await this.iamService.createPolicy({ + id: randomUUID(), + version: 1, + isDefault: true, + name: PolicyName, + path: Path, + description: Description, + policy: PolicyDocument, + accountId: awsProperties.accountId, + }); + + return policy.metadata; + } +} diff --git a/src/iam/create-role.handler.ts b/src/iam/create-role.handler.ts new file mode 100644 index 0000000..294baeb --- /dev/null +++ b/src/iam/create-role.handler.ts @@ -0,0 +1,51 @@ +import { Injectable } from '@nestjs/common'; +import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler'; +import { Action } from '../action.enum'; +import * as Joi from 'joi'; +import { IamService } from './iam.service'; +import { randomUUID } from 'crypto'; + +type QueryParams = { + RoleName: string; + Path: string; + AssumeRolePolicyDocument: string; + MaxSessionDuration: number; + Description: string; +} + +@Injectable() +export class CreateRoleHandler extends AbstractActionHandler { + + constructor( + private readonly iamService: IamService, + ) { + super(); + } + + format = Format.Xml; + action = Action.IamCreateRole; + validator = Joi.object({ + AssumeRolePolicyDocument: Joi.string().min(1).max(131072).required(), + Description: Joi.string().max(1000).allow(null, '').default(null), + MaxSessionDuration: Joi.number().min(3600).max(43200).default(3600), + Path: Joi.string().min(1).max(512).required(), + RoleName: Joi.string().min(1).max(64).required(), + }); + + protected async handle({ RoleName, Path, AssumeRolePolicyDocument, MaxSessionDuration, Description }: QueryParams, awsProperties: AwsProperties) { + + const role = await this.iamService.createRole({ + id: randomUUID(), + accountId: awsProperties.accountId, + name: RoleName, + path: Path, + assumeRolePolicy: AssumeRolePolicyDocument, + maxSessionDuration: MaxSessionDuration, + description: Description, + }); + + return { + Role: role.metadata, + } + } +} diff --git a/src/iam/delete-role.handler.ts b/src/iam/delete-role.handler.ts new file mode 100644 index 0000000..e1c6f86 --- /dev/null +++ b/src/iam/delete-role.handler.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@nestjs/common'; +import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler'; +import { Action } from '../action.enum'; +import * as Joi from 'joi'; +import { IamService } from './iam.service'; +import { NotFoundException } from '../aws-shared-entities/aws-exceptions'; + +type QueryParams = { + RoleName: string; +} + +@Injectable() +export class DeleteRoleHandler extends AbstractActionHandler { + + constructor( + private readonly iamService: IamService, + ) { + super(); + } + + format = Format.Xml; + action = Action.IamDeleteRole; + validator = Joi.object({ + RoleName: Joi.string().min(1).max(64).required(), + }); + + protected async handle({ RoleName }: QueryParams, awsProperties: AwsProperties) { + await this.iamService.deleteRoleByName(awsProperties.accountId, RoleName); + } +} diff --git a/src/iam/get-policy-version.handler.ts b/src/iam/get-policy-version.handler.ts new file mode 100644 index 0000000..d8f473c --- /dev/null +++ b/src/iam/get-policy-version.handler.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@nestjs/common'; +import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler'; +import { Action } from '../action.enum'; +import * as Joi from 'joi'; + +type QueryParams = { + PolicyArn: string; + VersionId: string; +} + +@Injectable() +export class GetPolicyVersionHandler extends AbstractActionHandler { + + constructor( + + ) { + super(); + } + + format = Format.Xml; + action = Action.IamGetPolicyVersion; + validator = Joi.object({ + PolicyArn: Joi.string().required(), + VersionId: Joi.string().required(), + }); + + protected async handle({ PolicyArn, VersionId }: QueryParams, awsProperties: AwsProperties) { + + } +} diff --git a/src/iam/get-policy.handler.ts b/src/iam/get-policy.handler.ts new file mode 100644 index 0000000..bdc7fb1 --- /dev/null +++ b/src/iam/get-policy.handler.ts @@ -0,0 +1,28 @@ +import { Injectable } from '@nestjs/common'; +import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler'; +import { Action } from '../action.enum'; +import * as Joi from 'joi'; + +type QueryParams = { + PolicyArn: string; +} + +@Injectable() +export class GetPolicyHandler extends AbstractActionHandler { + + constructor( + + ) { + super(); + } + + format = Format.Xml; + action = Action.IamGetPolicy; + validator = Joi.object({ + PolicyArn: Joi.string().required(), + }); + + protected async handle({ PolicyArn }: QueryParams, awsProperties: AwsProperties) { + + } +} diff --git a/src/iam/get-role.handler.ts b/src/iam/get-role.handler.ts new file mode 100644 index 0000000..cac7228 --- /dev/null +++ b/src/iam/get-role.handler.ts @@ -0,0 +1,39 @@ +import { Injectable } from '@nestjs/common'; +import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler'; +import { Action } from '../action.enum'; +import * as Joi from 'joi'; +import { IamService } from './iam.service'; +import { NotFoundException } from '../aws-shared-entities/aws-exceptions'; + +type QueryParams = { + RoleName: string; +} + +@Injectable() +export class GetRoleHandler extends AbstractActionHandler { + + constructor( + private readonly iamService: IamService, + ) { + super(); + } + + format = Format.Xml; + action = Action.IamGetRole; + validator = Joi.object({ + RoleName: Joi.string().min(1).max(64).required(), + }); + + protected async handle({ RoleName }: QueryParams, awsProperties: AwsProperties) { + + const role = await this.iamService.findOneRoleByName(awsProperties.accountId, RoleName); + + if (!role) { + throw new NotFoundException(); + } + + return { + Role: role.metadata, + } + } +} diff --git a/src/iam/iam-policy.entity.ts b/src/iam/iam-policy.entity.ts new file mode 100644 index 0000000..e716e03 --- /dev/null +++ b/src/iam/iam-policy.entity.ts @@ -0,0 +1,54 @@ +import { IamPolicy as PrismaIamPolicy } from "@prisma/client"; + +export class IamPolicy implements PrismaIamPolicy { + + id: string; + accountId: string; + name: string; + version: number; + isDefault: boolean; + policy: string; + path: string | null; + description: string | null; + isAttachable: boolean; + createdAt: Date; + updatedAt: Date; + + constructor(p: PrismaIamPolicy) { + this.id = p.id; + this.accountId = p.accountId; + this.name = p.name; + this.version = p.version; + this.isDefault = p.isDefault; + this.policy = p.policy; + this.path = p.path; + this.description = p.description; + this.isAttachable = p.isAttachable; + this.createdAt = p.createdAt; + this.updatedAt = p.updatedAt; + } + + get arn() { + const parts = ['policy']; + if (this.path && this.path !== '/') { + parts.push(this.path); + } + parts.push(this.name); + return `arn:aws:iam::${this.accountId}:${parts.join('/')}`; + } + + get metadata() { + return { + Arn: this.arn, + AttachmentCount: 0, + CreateDate: this.createdAt.toISOString(), + DefaultVersionId: `v${this.version}`, + Description: this.description, + IsAttachable: this.isAttachable, + Path: this.path, + PolicyId: this.id, + PolicyName: this.name, + UpdateDate: this.updatedAt.toISOString(), + } + } +} diff --git a/src/iam/iam-role.entity.ts b/src/iam/iam-role.entity.ts new file mode 100644 index 0000000..c7f340d --- /dev/null +++ b/src/iam/iam-role.entity.ts @@ -0,0 +1,52 @@ + +import { IamRole as PrismaIamRole } from '@prisma/client'; + +export class IamRole implements PrismaIamRole { + + accountId: string; + path: string | null; + name: string; + createdAt: Date; + id: string; + maxSessionDuration: number | null; + assumeRolePolicy: string | null; + description: string | null; + permissionBoundaryArn: string | null; + lastUsedDate: Date | null; + lastUsedRegion: string | null; + + constructor(p: PrismaIamRole) { + this.accountId = p.accountId; + this.path = p.path; + this.name = p.name; + this.createdAt = p.createdAt; + this.id = p.id; + this.maxSessionDuration = p.maxSessionDuration; + this.assumeRolePolicy = p.assumeRolePolicy; + this.description = p.description; + this.permissionBoundaryArn = p.permissionBoundaryArn; + this.lastUsedDate = p.lastUsedDate; + this.lastUsedRegion = p.lastUsedRegion; + } + + get arn() { + const parts = ['role']; + if (this.path && this.path !== '/') { + parts.push(this.path); + } + parts.push(this.name); + return `arn:aws:iam::${this.accountId}:${parts.join('/')}`; + } + + get metadata() { + return { + Path: this.path, + Arn: this.arn, + RoleName: this.name, + AssumeRolePolicyDocument: this.assumeRolePolicy, + CreateDate: this.createdAt.toISOString(), + RoleId: this.id, + MaxSessionDuration: this.maxSessionDuration, + } + } +} diff --git a/src/iam/iam.constants.ts b/src/iam/iam.constants.ts new file mode 100644 index 0000000..9cc27d3 --- /dev/null +++ b/src/iam/iam.constants.ts @@ -0,0 +1,5 @@ +import { AbstractActionHandler } from '../abstract-action.handler'; +import { Action } from '../action.enum'; + +export type IAMHandlers = Record; +export const IAMHandlers = Symbol.for('IAMHandlers'); diff --git a/src/iam/iam.module.ts b/src/iam/iam.module.ts new file mode 100644 index 0000000..5db95f8 --- /dev/null +++ b/src/iam/iam.module.ts @@ -0,0 +1,194 @@ +import { Module } from '@nestjs/common'; +import { Format } from '../abstract-action.handler'; +import { Action } from '../action.enum'; +import { AwsSharedEntitiesModule } from '../aws-shared-entities/aws-shared-entities.module'; +import { DefaultActionHandlerProvider } from '../default-action-handler/default-action-handler.provider'; +import { ExistingActionHandlersProvider } from '../default-action-handler/existing-action-handlers.provider'; +import { CreatePolicyHandler } from './create-policy.handler'; +import { CreateRoleHandler } from './create-role.handler'; +import { IAMHandlers } from './iam.constants'; +import { PrismaModule } from '../_prisma/prisma.module'; +import { IamService } from './iam.service'; +import { GetRoleHandler } from './get-role.handler'; + +const handlers = [ + CreatePolicyHandler, + CreateRoleHandler, + GetRoleHandler, +] + +const actions = [ + Action.IamAddClientIDToOpenIDConnectProvider, + Action.IamAddRoleToInstanceProfile, + Action.IamAddUserToGroup, + Action.IamAttachGroupPolicy, + Action.IamAttachRolePolicy, + Action.IamAttachUserPolicy, + Action.IamChangePassword, + Action.IamCreateAccessKey, + Action.IamCreateAccountAlias, + Action.IamCreateGroup, + Action.IamCreateInstanceProfile, + Action.IamCreateLoginProfile, + Action.IamCreateOpenIDConnectProvider, + Action.IamCreatePolicy, + Action.IamCreatePolicyVersion, + Action.IamCreateRole, + Action.IamCreateSAMLProvider, + Action.IamCreateServiceLinkedRole, + Action.IamCreateServiceSpecificCredential, + Action.IamCreateUser, + Action.IamCreateVirtualMFADevice, + Action.IamDeactivateMFADevice, + Action.IamDeleteAccessKey, + Action.IamDeleteAccountAlias, + Action.IamDeleteAccountPasswordPolicy, + Action.IamDeleteGroup, + Action.IamDeleteGroupPolicy, + Action.IamDeleteInstanceProfile, + Action.IamDeleteLoginProfile, + Action.IamDeleteOpenIDConnectProvider, + Action.IamDeletePolicy, + Action.IamDeletePolicyVersion, + Action.IamDeleteRole, + Action.IamDeleteRolePermissionsBoundary, + Action.IamDeleteRolePolicy, + Action.IamDeleteSAMLProvider, + Action.IamDeleteServerCertificate, + Action.IamDeleteServiceLinkedRole, + Action.IamDeleteServiceSpecificCredential, + Action.IamDeleteSigningCertificate, + Action.IamDeleteSSHPublicKey, + Action.IamDeleteUser, + Action.IamDeleteUserPermissionsBoundary, + Action.IamDeleteUserPolicy, + Action.IamDeleteVirtualMFADevice, + Action.IamDetachGroupPolicy, + Action.IamDetachRolePolicy, + Action.IamDetachUserPolicy, + Action.IamEnableMFADevice, + Action.IamGenerateCredentialReport, + Action.IamGenerateOrganizationsAccessReport, + Action.IamGenerateServiceLastAccessedDetails, + Action.IamGetAccessKeyLastUsed, + Action.IamGetAccountAuthorizationDetails, + Action.IamGetAccountPasswordPolicy, + Action.IamGetAccountSummary, + Action.IamGetContextKeysForCustomPolicy, + Action.IamGetContextKeysForPrincipalPolicy, + Action.IamGetCredentialReport, + Action.IamGetGroup, + Action.IamGetGroupPolicy, + Action.IamGetInstanceProfile, + Action.IamGetLoginProfile, + Action.IamGetOpenIDConnectProvider, + Action.IamGetOrganizationsAccessReport, + Action.IamGetPolicy, + Action.IamGetPolicyVersion, + Action.IamGetRole, + Action.IamGetRolePolicy, + Action.IamGetSAMLProvider, + Action.IamGetServerCertificate, + Action.IamGetServiceLastAccessedDetails, + Action.IamGetServiceLastAccessedDetailsWithEntities, + Action.IamGetServiceLinkedRoleDeletionStatus, + Action.IamGetSSHPublicKey, + Action.IamGetUser, + Action.IamGetUserPolicy, + Action.IamListAccessKeys, + Action.IamListAccountAliases, + Action.IamListAttachedGroupPolicies, + Action.IamListAttachedRolePolicies, + Action.IamListAttachedUserPolicies, + Action.IamListEntitiesForPolicy, + Action.IamListGroupPolicies, + Action.IamListGroups, + Action.IamListGroupsForUser, + Action.IamListInstanceProfiles, + Action.IamListInstanceProfilesForRole, + Action.IamListInstanceProfileTags, + Action.IamListMFADevices, + Action.IamListMFADeviceTags, + Action.IamListOpenIDConnectProviders, + Action.IamListOpenIDConnectProviderTags, + Action.IamListPolicies, + Action.IamListPoliciesGrantingServiceAccess, + Action.IamListPolicyTags, + Action.IamListPolicyVersions, + Action.IamListRolePolicies, + Action.IamListRoles, + Action.IamListRoleTags, + Action.IamListSAMLProviders, + Action.IamListSAMLProviderTags, + Action.IamListServerCertificates, + Action.IamListServerCertificateTags, + Action.IamListServiceSpecificCredentials, + Action.IamListSigningCertificates, + Action.IamListSSHPublicKeys, + Action.IamListUserPolicies, + Action.IamListUsers, + Action.IamListUserTags, + Action.IamListVirtualMFADevices, + Action.IamPutGroupPolicy, + Action.IamPutRolePermissionsBoundary, + Action.IamPutRolePolicy, + Action.IamPutUserPermissionsBoundary, + Action.IamPutUserPolicy, + Action.IamRemoveClientIDFromOpenIDConnectProvider, + Action.IamRemoveRoleFromInstanceProfile, + Action.IamRemoveUserFromGroup, + Action.IamResetServiceSpecificCredential, + Action.IamResyncMFADevice, + Action.IamSetDefaultPolicyVersion, + Action.IamSetSecurityTokenServicePreferences, + Action.IamSimulateCustomPolicy, + Action.IamSimulatePrincipalPolicy, + Action.IamTagInstanceProfile, + Action.IamTagMFADevice, + Action.IamTagOpenIDConnectProvider, + Action.IamTagPolicy, + Action.IamTagRole, + Action.IamTagSAMLProvider, + Action.IamTagServerCertificate, + Action.IamTagUser, + Action.IamUntagInstanceProfile, + Action.IamUntagMFADevice, + Action.IamUntagOpenIDConnectProvider, + Action.IamUntagPolicy, + Action.IamUntagRole, + Action.IamUntagSAMLProvider, + Action.IamUntagServerCertificate, + Action.IamUntagUser, + Action.IamUpdateAccessKey, + Action.IamUpdateAccountPasswordPolicy, + Action.IamUpdateAssumeRolePolicy, + Action.IamUpdateGroup, + Action.IamUpdateLoginProfile, + Action.IamUpdateOpenIDConnectProviderThumbprint, + Action.IamUpdateRole, + Action.IamUpdateRoleDescription, + Action.IamUpdateSAMLProvider, + Action.IamUpdateServerCertificate, + Action.IamUpdateServiceSpecificCredential, + Action.IamUpdateSigningCertificate, + Action.IamUpdateSSHPublicKey, + Action.IamUpdateUser, + Action.IamUploadServerCertificate, + Action.IamUploadSigningCertificate, + Action.IamUploadSSHPublicKey, +] + +@Module({ + imports: [ + AwsSharedEntitiesModule, + PrismaModule, + ], + providers: [ + ...handlers, + IamService, + ExistingActionHandlersProvider(handlers), + DefaultActionHandlerProvider(IAMHandlers, Format.Xml, actions), + ], + exports: [IAMHandlers], +}) +export class IamModule {} diff --git a/src/iam/iam.service.ts b/src/iam/iam.service.ts new file mode 100644 index 0000000..7c4c865 --- /dev/null +++ b/src/iam/iam.service.ts @@ -0,0 +1,49 @@ +import { Injectable } from "@nestjs/common"; + +import { PrismaService } from "../_prisma/prisma.service"; +import { Prisma } from "@prisma/client"; +import { IamPolicy } from "./iam-policy.entity"; +import { IamRole } from "./iam-role.entity"; +import { EntityAlreadyExists } from "../aws-shared-entities/aws-exceptions"; + +@Injectable() +export class IamService { + + constructor( + private readonly prismaService: PrismaService, + ) {} + + async createRole(data: Prisma.IamRoleCreateInput): Promise { + try { + const record = await this.prismaService.iamRole.create({ data }); + return new IamRole(record); + } catch (err) { + throw new EntityAlreadyExists(`RoleName ${data.name} already exists`); + } + } + + async findOneRoleByName(accountId: string, name: string): Promise { + const record = await this.prismaService.iamRole.findFirst({ + where: { + name, + accountId, + } + }); + + return record ? new IamRole(record) : null; + } + + async deleteRoleByName(accountId: string, name: string) { + await this.prismaService.iamRole.deleteMany({ + where: { + name, + accountId, + } + }); + } + + async createPolicy(data: Prisma.IamPolicyCreateInput): Promise { + const record = await this.prismaService.iamPolicy.create({ data }); + return new IamPolicy(record); + } +} diff --git a/src/iam/list-attached-role-policies.ts b/src/iam/list-attached-role-policies.ts new file mode 100644 index 0000000..84c3406 --- /dev/null +++ b/src/iam/list-attached-role-policies.ts @@ -0,0 +1,28 @@ +import { Injectable } from '@nestjs/common'; +import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler'; +import { Action } from '../action.enum'; +import * as Joi from 'joi'; + +type QueryParams = { + RoleName: string; +} + +@Injectable() +export class ListAttachedRolePoliciesHandler extends AbstractActionHandler { + + constructor( + ) { + super(); + } + + format = Format.Xml; + action = Action.IamListAttachedRolePolicies; + validator = Joi.object({ + RoleName: Joi.string().required(), + }); + + protected async handle({ RoleName }: QueryParams, awsProperties: AwsProperties) { + + + } +} diff --git a/src/iam/list-role-policies.handler.ts b/src/iam/list-role-policies.handler.ts new file mode 100644 index 0000000..173c884 --- /dev/null +++ b/src/iam/list-role-policies.handler.ts @@ -0,0 +1,31 @@ +import { Injectable } from '@nestjs/common'; +import { AbstractActionHandler, AwsProperties, Format } from '../abstract-action.handler'; +import { Action } from '../action.enum'; +import * as Joi from 'joi'; + +type QueryParams = { + Marker: string; + MaxItems: number; + RoleName: string; +} + +@Injectable() +export class ListRolePoliciesHandler extends AbstractActionHandler { + + constructor( + ) { + super(); + } + + format = Format.Xml; + action = Action.IamListRolePolicies; + validator = Joi.object({ + Marker: Joi.string().allow(null), + MaxItems: Joi.number().min(1).max(1000).default(100), + RoleName: Joi.string().required(), + }); + + protected async handle({ RoleName }: QueryParams, awsProperties: AwsProperties) { + + } +}