??DynamoDB Best Practices Using Terraform, IAM Configurations, and NestJS with Repositories??

??DynamoDB Best Practices Using Terraform, IAM Configurations, and NestJS with Repositories??

Developing scalable, secure, and modular applications is essential in today’s fast-paced tech landscape. Here's how I achieve it by combining: 1?? Terraform for Infrastructure as Code (IaC) 2?? IAM Configurations for Security and Access Control 3?? NestJS with Repository Pattern for Clean Architecture

I follow a corporate-level folder structure for clarity, modularity, and scalability:


Folder Structure

project-root/

├── src/

│ ├── controllers/

│ │ └── user.controller.ts

│ ├── services/

│ │ └── user.service.ts

│ ├── models/

│ │ └── user.model.ts

│ ├── dynamoDB/

│ │ ├── dynamoDB.service.ts

│ │ └── dynamoDB.config.ts

│ ├── app.module.ts

│ ├── app.ts

│ └── main.ts

├── terraform/

│ ├── global/

│ │ └── main.tf

│ ├── common/

│ │ ├── dynamodb.tf

│ │ ├── iam.tf

│ │ └── s3.tf

│ ├── dev/

│ │ ├── main.tf

│ │ ├── variables.tf

│ │ └── outputs.tf

│ ├── stage/

│ │ ├── main.tf

│ │ ├── variables.tf

│ │ └── outputs.tf

│ └── prod/

│ ├── main.tf

│ ├── variables.tf

│ └── outputs.tf



1?? Setting Up IAM Policy and Role for DynamoDB

Incorporate security best practices by defining least-privilege access with Terraform:

File: common/dynamodb.tf

This file sets up a reusable DynamoDB table configuration that can be referenced in different environments.

resource "aws_dynamodb_table" "main" {
  name           = var.table_name
  billing_mode   = "PAY_PER_REQUEST"
  hash_key       = "PK"
  range_key      = "SK"
  attribute {
    name = "PK"
    type = "S"
  }
  attribute {
    name = "SK"
    type = "S"
  }

  tags = {
    Environment = var.environment
  }
}

output "table_name" {
  value = aws_dynamodb_table.main.name
}

output "table_arn" {
  value = aws_dynamodb_table.main.arn
}
        

common/iam.tf

resource "aws_iam_policy" "dynamodb_policy" {
  name        = "DynamoDBAccessPolicy"
  description = "Policy to allow access to DynamoDB"
  policy      = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Sid      = "DynamoDBReadWrite",
        Effect   = "Allow",
        Action   = [
          "dynamodb:GetItem",
          "dynamodb:PutItem",
          "dynamodb:UpdateItem",
          "dynamodb:Query",
          "dynamodb:Scan"
        ],
        Resource = "arn:aws:dynamodb:us-east-1:123456789012:table/UsersTable"
      }
    ]
  })
}

resource "aws_iam_role" "dynamodb_role" {
  name               = "DynamoDBAccessRole"
  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Effect = "Allow",
        Principal = {
          Service = "lambda.amazonaws.com"
        },
        Action = "sts:AssumeRole"
      }
    ]
  })
}        

file common/s3.tf

This file defines a reusable S3 bucket configuration for different environments.

resource "aws_s3_bucket" "main" {
  bucket        = "${var.bucket_name}-${var.environment}"
  acl           = "private"
  force_destroy = true

  versioning {
    enabled = true
  }

  tags = {
    Environment = var.environment
  }
}

output "bucket_name" {
  value = aws_s3_bucket.main.bucket
}

output "bucket_arn" {
  value = aws_s3_bucket.main.arn
}
        

2?? DynamoDB Repository Pattern in NestJS

Leverage the repository pattern for cleaner, testable, and decoupled code:

DynamoDB Service: src/dynamoDB/dynamoDB.service.ts

import { Injectable } from '@nestjs/common';
import { DynamoDB } from 'aws-sdk';

@Injectable()
export class DynamoDBService {
  private readonly dynamoDb = new DynamoDB.DocumentClient();

  async getItem(params: DynamoDB.DocumentClient.GetItemInput) {
    return await this.dynamoDb.get(params).promise();
  }

  async putItem(params: DynamoDB.DocumentClient.PutItemInput) {
    return await this.dynamoDb.put(params).promise();
  }
}        

dynamoDB/dynamoDB.config.ts

Contains DynamoDB configurations.

export const DynamoDBConfig = {
  tableName: 'UsersTable',
  region: 'us-east-1',
};        

user.controller.ts

Handles HTTP requests and delegates logic to the service layer.

import { Controller, Get, Post, Body, Param } from '@nestjs/common';
import { UserService } from '../services/user.service';
import { User } from '../models/user.model';

@Controller('users')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Get(':id')
  async getUser(@Param('id') id: string): Promise<User> {
    return this.userService.getUserById(id);
  }

  @Post()
  async createUser(@Body() user: User): Promise<void> {
    await this.userService.createUser(user);
  }
}        

user.service.ts

Contains business logic.

import { Injectable } from '@nestjs/common';
import { UserRepository } from '../models/user.repository';
import { User } from '../models/user.model';

@Injectable()
export class UserService {
  constructor(private readonly userRepository: UserRepository) {}

  async getUserById(id: string): Promise<User> {
    return this.userRepository.findUserById(id);
  }

  async createUser(user: User): Promise<void> {
    await this.userRepository.createUser(user);
  }
}        

user.model.ts

Defines the User model.

export class User {
  userId: string;
  name: string;
  email: string;
}        

app.module.ts

Registers all modules and services.

import { Module } from '@nestjs/common';
import { UserController } from './controllers/user.controller';
import { UserService } from './services/user.service';
import { DynamoDBService } from './dynamoDB/dynamoDB.service';

@Module({
  imports: [],
  controllers: [UserController],
  providers: [UserService, DynamoDBService],
})
export class AppModule {}        

app.ts

Contains application-level initialization logic.

import './app';        

3?? Environment-Specific Terraform Configurations

Use reusable modules and maintain separate configurations for dev, stage, and prod environments.

File: terraform/dev/main.tf

provider "aws" {
  region = var.region
}

module "dynamodb" {
  source    = "../common"
  table_name = var.table_name
}

module "iam" {
  source       = "../common"
  policy_name  = var.policy_name
  role_name    = var.role_name
  dynamodb_arn = module.dynamodb.table_arn
}
        

File: terraform/dev/outputs.tf

output "dynamodb_table_name" {
  description = "The name of the DynamoDB table"
  value       = module.dynamodb.table_name
}

output "dynamodb_table_arn" {
  description = "The ARN of the DynamoDB table"
  value       = module.dynamodb.table_arn
}

output "iam_policy_arn" {
  description = "The ARN of the IAM policy created"
  value       = module.iam.policy_arn
}

output "iam_role_arn" {
  description = "The ARN of the IAM role created"
  value       = module.iam.role_arn
}
        

File: terraform/dev/variables.tf

variable "region" {
  type        = string
  description = "AWS region for deployment"
}

variable "table_name" {
  type        = string
  description = "Name of the DynamoDB table"
}

variable "policy_name" {
  type        = string
  description = "Name of the IAM policy"
}

variable "role_name" {
  type        = string
  description = "Name of the IAM role"
}

variable "environment" {
  type        = string
  description = "The deployment environment (e.g., dev, stage, prod)"
}

variable "bucket_name" {
  type        = string
  description = "The name of the S3 bucket"
}

variable "bucket_arn" {
  type        = string
  description = "The name of the S3 bucket
}        

Conclusion

Using this well-structured approach, you can build secure, scalable, and maintainable applications. Combining Terraform, IAM configurations, and NestJS ensures seamless integration between infrastructure and application layers.

?? What are your best practices for cloud-native development? Share your thoughts in the comments!

#AWS #DynamoDB #Terraform #NestJS #RepositoryPattern #InfrastructureAsCode #CloudComputing #DevOps #zomato #google #linkedIn #news #like #follow

Shubham A.

Certified ForgeRock AM and CIAM 2X Specialist | OKTA 2X Certified | Transmit Consultant | Ex KPMG | JAVA | IAM | OpenAM | OpenDJ | AWS|

3 个月

Great approach! Combining Terraform, IAM, and NestJS is a smart way to build scalable and secure applications. Clean architecture is always a win

要查看或添加评论,请登录

Kishan Maurya的更多文章

社区洞察

其他会员也浏览了