feat: crud-pricing initial implementation
All checks were successful
kinec.tech/airun-pathfinder-crud-pricing/pipeline/head This commit looks good

Complete CRUD service for AWS pricing operations - single source of truth.

Features:
- Dual pricing model (retail + account-specific with auto EDP/PPA detection)
- Get/Put pricing operations with intelligent caching
- AWS Pricing API integration for public list prices
- AWS Cost Explorer integration for account-specific pricing
- Access counting for self-learning 14-day refresh
- Query most-accessed instances (powers smart refresh)
- TTL: 30 days (retail), 7 days (account-specific)

Architecture:
- All other lambdas use this for pricing operations
- No direct DynamoDB access from other components
- Consistent schema enforcement
- Complete IAM setup for Pricing API, Cost Explorer, STS

Infrastructure:
- Complete Terraform configuration
- Full CI/CD pipeline (Jenkinsfile)
- Comprehensive documentation
- Production-ready scaffolding

Part of Phase 1 - foundation for pricing system.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-27 04:20:56 -05:00
commit e88609d724
13 changed files with 2494 additions and 0 deletions

171
terraform/main.tf Normal file
View File

@@ -0,0 +1,171 @@
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.23"
}
}
}
provider "aws" {
region = var.aws_region
default_tags {
tags = {
Project = "airun-pathfinder"
Component = "crud"
Service = "pricing"
Environment = var.environment
ManagedBy = "terraform"
}
}
}
# Get current AWS account ID
data "aws_caller_identity" "current" {}
# Lambda function
resource "aws_lambda_function" "crud_pricing" {
filename = "../target/lambda/bootstrap/bootstrap.zip"
function_name = "airun-pathfinder-crud-pricing-${var.environment}"
role = aws_iam_role.lambda.arn
handler = "bootstrap"
runtime = "provided.al2023"
architectures = ["arm64"]
timeout = var.lambda_timeout
memory_size = var.lambda_memory
source_code_hash = filebase64sha256("../target/lambda/bootstrap/bootstrap.zip")
environment {
variables = {
RUST_LOG = var.log_level
TABLE_NAME = local.table_name
ENVIRONMENT = var.environment
}
}
# Enable X-Ray tracing for observability
tracing_config {
mode = "Active"
}
tags = {
Name = "airun-pathfinder-crud-pricing"
}
}
# CloudWatch Log Group
resource "aws_cloudwatch_log_group" "crud_pricing" {
name = "/aws/lambda/${aws_lambda_function.crud_pricing.function_name}"
retention_in_days = var.log_retention_days
tags = {
Name = "crud-pricing-logs"
}
}
# IAM Role for Lambda
resource "aws_iam_role" "lambda" {
name = "airun-pathfinder-crud-pricing-role-${var.environment}"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "lambda.amazonaws.com"
}
}]
})
tags = {
Name = "airun-pathfinder-crud-pricing-role"
}
}
# Basic Lambda execution policy
resource "aws_iam_role_policy_attachment" "lambda_basic" {
role = aws_iam_role.lambda.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
# X-Ray permissions for tracing
resource "aws_iam_role_policy_attachment" "lambda_xray" {
role = aws_iam_role.lambda.name
policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
}
# DynamoDB access policy
resource "aws_iam_role_policy" "dynamodb_access" {
name = "airun-pathfinder-crud-pricing-dynamodb-policy"
role = aws_iam_role.lambda.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:UpdateItem",
"dynamodb:Query"
]
Resource = [
"arn:aws:dynamodb:${var.aws_region}:${data.aws_caller_identity.current.account_id}:table/${local.table_name}",
"arn:aws:dynamodb:${var.aws_region}:${data.aws_caller_identity.current.account_id}:table/${local.table_name}/index/AccessCountIndex"
]
}
]
})
}
# AWS Pricing API access
resource "aws_iam_role_policy" "pricing_api_access" {
name = "airun-pathfinder-crud-pricing-pricing-api-policy"
role = aws_iam_role.lambda.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"pricing:GetProducts",
"pricing:DescribeServices",
"pricing:GetAttributeValues"
]
Resource = "*"
}
]
})
}
# STS AssumeRole access (for Cost Explorer in customer accounts)
resource "aws_iam_role_policy" "sts_assume_role" {
name = "airun-pathfinder-crud-pricing-sts-policy"
role = aws_iam_role.lambda.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = "sts:AssumeRole"
Resource = "arn:aws:iam::*:role/pathfinder-pricing-access"
}
]
})
}
# Cost Explorer access (when assuming role)
# Note: This is granted via the role in the customer account, not here
# Local variables
locals {
table_name = var.table_name != "" ? var.table_name : "pathfinder-${var.environment}-pricing"
}