Repository: cycloidio/terracost
Pull request #131 (2025-01-28 14:37:17)

aws: implement new resources
fix https://github.com/cycloidio/terracost/issues/129


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5baa254..a807d9b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,11 @@
 - Now HCL functions are loaded so no more errors related to functions missing
   ([Issue #126](https://github.com/cycloidio/terracost/issue/126))
 
+### Added
+
+- AWS support for `aws_cloudwatch_log_group`, `aws_cloudwatch_metric_alarm`, `aws_kms_key`, `aws_rds_cluster`, `aws_rds_cluster_instance`, `aws_s3_bucket`, `aws_s3_bucket_analytics_configuration`, `aws_s3_bucket_inventory`, `aws_secretsmanager_secret`, `aws_sqs_queue`
+  ([Pull #131](https://github.com/cycloidio/terracost/pull/115))
+
 ## [0.5.2] _2024-11-05_
 
 ### Added
diff --git a/aws/field/field.go b/aws/field/field.go
index c8efec4..415c56f 100644
--- a/aws/field/field.go
+++ b/aws/field/field.go
@@ -42,6 +42,9 @@ const (
 	ThroughputCapacity         // Throughput capacity
 	FileSystemDeploymentOption // Deployment option
 
+	// CloudWatch Alarm fields
+	AlarmType // Alarm Type
+
 	///// Price Attributes /////
 	Currency      // Currency
 	PricePerUnit  // PricePerUnit
diff --git a/aws/field/field_gen.go b/aws/field/field_gen.go
index 3c7a505..5738851 100644
--- a/aws/field/field_gen.go
+++ b/aws/field/field_gen.go
@@ -7,11 +7,11 @@ import (
 	"strings"
 )
 
-const _FieldName = "SKUCapacityStatusGroupInstance TypeLocationOperating SystemPre Installed S/WProduct FamilyserviceCodeTenancyusageTypeVolume API NameVolume TypeStorage ClassAccess TypeThroughput ClassCache EngineDatabase EngineDatabase EditionDeployment OptionLicense ModelFile system typeStorage typeThroughput capacityDeployment optionCurrencyPricePerUnitStartingRangeTermTypeUnit"
+const _FieldName = "SKUCapacityStatusGroupInstance TypeLocationOperating SystemPre Installed S/WProduct FamilyserviceCodeTenancyusageTypeVolume API NameVolume TypeStorage ClassAccess TypeThroughput ClassCache EngineDatabase EngineDatabase EditionDeployment OptionLicense ModelFile system typeStorage typeThroughput capacityDeployment optionAlarm TypeCurrencyPricePerUnitStartingRangeTermTypeUnit"
 
-var _FieldIndex = [...]uint16{0, 3, 17, 22, 35, 43, 59, 76, 90, 101, 108, 117, 132, 143, 156, 167, 183, 195, 210, 226, 243, 256, 272, 284, 303, 320, 328, 340, 353, 361, 365}
+var _FieldIndex = [...]uint16{0, 3, 17, 22, 35, 43, 59, 76, 90, 101, 108, 117, 132, 143, 156, 167, 183, 195, 210, 226, 243, 256, 272, 284, 303, 320, 330, 338, 350, 363, 371, 375}
 
-const _FieldLowerName = "skucapacitystatusgroupinstance typelocationoperating systempre installed s/wproduct familyservicecodetenancyusagetypevolume api namevolume typestorage classaccess typethroughput classcache enginedatabase enginedatabase editiondeployment optionlicense modelfile system typestorage typethroughput capacitydeployment optioncurrencypriceperunitstartingrangetermtypeunit"
+const _FieldLowerName = "skucapacitystatusgroupinstance typelocationoperating systempre installed s/wproduct familyservicecodetenancyusagetypevolume api namevolume typestorage classaccess typethroughput classcache enginedatabase enginedatabase editiondeployment optionlicense modelfile system typestorage typethroughput capacitydeployment optionalarm typecurrencypriceperunitstartingrangetermtypeunit"
 
 func (i Field) String() string {
 	if i >= Field(len(_FieldIndex)-1) {
@@ -49,14 +49,15 @@ func _FieldNoOp() {
 	_ = x[StorageType-(22)]
 	_ = x[ThroughputCapacity-(23)]
 	_ = x[FileSystemDeploymentOption-(24)]
-	_ = x[Currency-(25)]
-	_ = x[PricePerUnit-(26)]
-	_ = x[StartingRange-(27)]
-	_ = x[TermType-(28)]
-	_ = x[Unit-(29)]
+	_ = x[AlarmType-(25)]
+	_ = x[Currency-(26)]
+	_ = x[PricePerUnit-(27)]
+	_ = x[StartingRange-(28)]
+	_ = x[TermType-(29)]
+	_ = x[Unit-(30)]
 }
 
-var _FieldValues = []Field{SKU, CapacityStatus, Group, InstanceType, Location, OperatingSystem, PreInstalledSW, ProductFamily, ServiceCode, Tenancy, UsageType, VolumeAPIName, VolumeType, StorageClass, AccessType, ThroughputClass, CacheEngine, DatabaseEngine, DatabaseEdition, DatabaseDeploymentOption, LicenseModel, FileSystemType, StorageType, ThroughputCapacity, FileSystemDeploymentOption, Currency, PricePerUnit, StartingRange, TermType, Unit}
+var _FieldValues = []Field{SKU, CapacityStatus, Group, InstanceType, Location, OperatingSystem, PreInstalledSW, ProductFamily, ServiceCode, Tenancy, UsageType, VolumeAPIName, VolumeType, StorageClass, AccessType, ThroughputClass, CacheEngine, DatabaseEngine, DatabaseEdition, DatabaseDeploymentOption, LicenseModel, FileSystemType, StorageType, ThroughputCapacity, FileSystemDeploymentOption, AlarmType, Currency, PricePerUnit, StartingRange, TermType, Unit}
 
 var _FieldNameToValueMap = map[string]Field{
 	_FieldName[0:3]:          SKU,
@@ -109,16 +110,18 @@ var _FieldNameToValueMap = map[string]Field{
 	_FieldLowerName[284:303]: ThroughputCapacity,
 	_FieldName[303:320]:      FileSystemDeploymentOption,
 	_FieldLowerName[303:320]: FileSystemDeploymentOption,
-	_FieldName[320:328]:      Currency,
-	_FieldLowerName[320:328]: Currency,
-	_FieldName[328:340]:      PricePerUnit,
-	_FieldLowerName[328:340]: PricePerUnit,
-	_FieldName[340:353]:      StartingRange,
-	_FieldLowerName[340:353]: StartingRange,
-	_FieldName[353:361]:      TermType,
-	_FieldLowerName[353:361]: TermType,
-	_FieldName[361:365]:      Unit,
-	_FieldLowerName[361:365]: Unit,
+	_FieldName[320:330]:      AlarmType,
+	_FieldLowerName[320:330]: AlarmType,
+	_FieldName[330:338]:      Currency,
+	_FieldLowerName[330:338]: Currency,
+	_FieldName[338:350]:      PricePerUnit,
+	_FieldLowerName[338:350]: PricePerUnit,
+	_FieldName[350:363]:      StartingRange,
+	_FieldLowerName[350:363]: StartingRange,
+	_FieldName[363:371]:      TermType,
+	_FieldLowerName[363:371]: TermType,
+	_FieldName[371:375]:      Unit,
+	_FieldLowerName[371:375]: Unit,
 }
 
 var _FieldNames = []string{
@@ -147,11 +150,12 @@ var _FieldNames = []string{
 	_FieldName[272:284],
 	_FieldName[284:303],
 	_FieldName[303:320],
-	_FieldName[320:328],
-	_FieldName[328:340],
-	_FieldName[340:353],
-	_FieldName[353:361],
-	_FieldName[361:365],
+	_FieldName[320:330],
+	_FieldName[330:338],
+	_FieldName[338:350],
+	_FieldName[350:363],
+	_FieldName[363:371],
+	_FieldName[371:375],
 }
 
 // FieldString retrieves an enum value from the enum constants string name.
diff --git a/aws/filter.go b/aws/filter.go
index aa19057..894293f 100644
--- a/aws/filter.go
+++ b/aws/filter.go
@@ -16,22 +16,32 @@ func DefaultFilter(_ *price.WithProduct) bool {
 // MinimalFilter only ingests the supported records, skipping those that would never be used.
 func MinimalFilter(pp *price.WithProduct) bool {
 	switch pp.Product.Service {
+	case "AmazonCloudWatch":
+		return minimalFilterCloudWatch(pp)
 	case "AmazonEC2":
 		return minimalFilterEC2(pp)
+	case "AmazonEFS":
+		return true // is minimal already
+	case "AmazonEKS":
+		return true // is minimal already
+	case "AmazonElastiCache":
+		return true // is minimal already
+	case "AmazonFSx":
+		return true
 	case "AmazonRDS":
 		return minimalFilterRDS(pp)
+	case "AmazonS3":
+		return minimalFilterS3Bucket(pp)
+	case "AWSDataTransfer":
+		return true
 	case "AWSELB":
 		return true // is minimal already
-	case "AmazonElastiCache":
-		return true // is minimal already
-	case "AmazonCloudWatch":
+	case "awskms":
 		return true // is minimal already
-	case "AmazonEKS":
+	case "AWSQueueService":
 		return true // is minimal already
-	case "AmazonEFS":
+	case "AWSSecretsManager":
 		return true // is minimal already
-	case "AmazonFSx":
-		return true
 	default:
 		return false
 	}
@@ -60,10 +70,29 @@ func minimalFilterEC2(pp *price.WithProduct) bool {
 	}
 }
 
+// minimalFilterCloudWatch only ingests records of supported product families.
+func minimalFilterCloudWatch(pp *price.WithProduct) bool {
+	switch pp.Product.Family {
+	case "Data Payload", "Storage Snapshot", "Alarm":
+		return true
+	default:
+		return false
+	}
+}
+
 // minimalFilterRDS only ingests RDS records of supported product families.
 func minimalFilterRDS(pp *price.WithProduct) bool {
 	switch pp.Product.Family {
-	case "Database Instance", "Database Storage", "Provisioned IOPS":
+	case "Database Instance", "Database Storage", "Provisioned IOPS", "Serverless", "ServerlessV2", "System Operation", "Storage Snapshot", "Performance Insights":
+		return true
+	default:
+		return false
+	}
+}
+
+func minimalFilterS3Bucket(pp *price.WithProduct) bool {
+	switch pp.Product.Family {
+	case "Storage", "API Request", "Fee":
 		return true
 	default:
 		return false
diff --git a/aws/ingester.go b/aws/ingester.go
index 5b766a7..0ba0441 100644
--- a/aws/ingester.go
+++ b/aws/ingester.go
@@ -220,6 +220,9 @@ var columnProductToIngest = map[field.Field]string{
 	field.StorageType:                "StorageType",
 	field.ThroughputCapacity:         "ThroughputCapacity",
 	field.FileSystemDeploymentOption: "Deployment_option",
+
+	// Cloudwatch alarms
+	field.AlarmType: "AlarmType",
 }
 
 // columnPriceToIngest is a mapping from column title to the price.Price attribute name under which the value will
diff --git a/aws/region/regions.go b/aws/region/regions.go
index 87bd560..c7b0079 100644
--- a/aws/region/regions.go
+++ b/aws/region/regions.go
@@ -8,19 +8,27 @@ var nameToCode = map[string]Code{
 	"US West (Oregon)":           "us-west-2",
 	"US West (Los Angeles)":      "us-west-2-lax-1", // Included in the offer file but missing from the docs.
 	"Canada (Central)":           "ca-central-1",
+	"Canada West (Calgary)":      "ca-west-1",
 	"EU (Stockholm)":             "eu-north-1",
 	"EU (Ireland)":               "eu-west-1",
 	"EU (London)":                "eu-west-2",
 	"EU (Paris)":                 "eu-west-3",
 	"EU (Frankfurt)":             "eu-central-1",
+	"EU (Zurich)":                "eu-central-2",
 	"EU (Milan)":                 "eu-south-1",
-	"Asia Pacific (Mumbai)":      "ap-south-1",
+	"EU (Spain)":                 "eu-south-2",
 	"Asia Pacific (Tokyo)":       "ap-northeast-1",
 	"Asia Pacific (Seoul)":       "ap-northeast-2",
 	"Asia Pacific (Osaka-Local)": "ap-northeast-3",
 	"Asia Pacific (Singapore)":   "ap-southeast-1",
 	"Asia Pacific (Sydney)":      "ap-southeast-2",
+	"Asie Pacific (Jakarta)":     "ap-southeast-3",
+	"Asia Pacific (Melbourne)":   "ap-southeast-4",
+	"Asie Pacific (Malaysia)":    "ap-southeast-5",
+	"Asie Pacific (Thailand)":    "ap-southeast-7",
 	"Asia Pacific (Hong Kong)":   "ap-east-1",
+	"Asia Pacific (Mumbai)":      "ap-south-1",
+	"Asie Pacific (Hyderabad)":   "ap-south-2",
 	"South America (Sao Paulo)":  "sa-east-1",
 	"China (Beijing)":            "cn-north-1",
 	"China (Ningxia)":            "cn-northwest-1",
@@ -28,6 +36,49 @@ var nameToCode = map[string]Code{
 	"AWS GovCloud (US-East)":     "us-gov-east-1",
 	"Middle East (Bahrain)":      "me-south-1",
 	"Africa (Cape Town)":         "af-south-1",
+	"Israel (Tel Aviv)":          "il-central-1",
+	"Middle East (UAE)":          "me-central-1",
+}
+
+// Short billing Region code
+// https://docs.aws.amazon.com/AmazonS3/latest/userguide/aws-usage-report-understand.html
+var codeToShortName = map[string]string{
+	"us-east-1":       "US",
+	"us-east-2":       "USE2",
+	"us-west-1":       "USW1",
+	"us-west-2":       "USW2",
+	"us-west-2-lax-1": "LAX1",
+	"ca-central-1":    "CAN1",
+	"ca-west-1":       "CAW1",
+	"eu-north-1":      "EUN1",
+	"eu-west-1":       "EU",
+	"eu-west-2":       "EUW2",
+	"eu-west-3":       "EUW3",
+	"eu-central-1":    "EUC1",
+	"eu-central-2":    "EUC2",
+	"eu-south-1":      "EUS1",
+	"eu-south-2":      "EUS2",
+	"ap-south-1":      "APS3",
+	"ap-northeast-1":  "APN1",
+	"ap-northeast-2":  "APN2",
+	"ap-northeast-3":  "APN3",
+	"ap-southeast-1":  "APS1",
+	"ap-southeast-2":  "APS2",
+	"ap-southeast-3":  "APS3",
+	"ap-southeast-4":  "APS6",
+	"ap-southeast-5":  "APS7",
+	"ap-southeast-7":  "APS9",
+	"ap-east-1":       "APE1",
+	"ap-south-2":      "APS5",
+	"sa-east-1":       "SAE1",
+	"cn-north-1":      "CNN1",
+	"cn-northwest-1":  "CNW1",
+	"us-gov-west-1":   "UGW1",
+	"us-gov-east-1":   "UGE1",
+	"me-south-1":      "MES1",
+	"af-south-1":      "AFS1",
+	"il-central-1":    "ILC1",
+	"me-central-1":    "MEC1",
 }
 
 var codeToName = make(map[Code]string)
@@ -37,3 +88,8 @@ func init() {
 		codeToName[code] = name
 	}
 }
+
+// GetRegionToShortName returns the short billing Region code for a region, which is the code that AWS commonly use in UsageType for billing purposes.
+func GetRegionToShortName(region string) string {
+	return codeToShortName[region]
+}
diff --git a/aws/services.go b/aws/services.go
index b6ddfdc..2088fb9 100644
--- a/aws/services.go
+++ b/aws/services.go
@@ -6,14 +6,19 @@ import (
 
 // SupportedServices is a list of all AWS services that are supported by Terracost.
 var supportedServices = map[string]struct{}{
+	"AmazonCloudWatch":  {},
 	"AmazonEC2":         {},
 	"AmazonEFS":         {},
 	"AmazonEKS":         {},
+	"AmazonElastiCache": {},
 	"AmazonFSx":         {},
 	"AmazonRDS":         {},
-	"AmazonElastiCache": {},
-	"AmazonCloudWatch":  {},
+	"AmazonS3":          {},
+	"AWSDataTransfer":   {},
 	"AWSELB":            {},
+	"awskms":            {},
+	"AWSQueueService":   {},
+	"AWSSecretsManager": {},
 }
 
 // IsServiceSupported returns true if the AWS service is valid and supported by Terracost (e.g. for ingestion.)
diff --git a/aws/terraform/cloudwatch_log_group.go b/aws/terraform/cloudwatch_log_group.go
new file mode 100644
index 0000000..f85cc5f
--- /dev/null
+++ b/aws/terraform/cloudwatch_log_group.go
@@ -0,0 +1,152 @@
+package terraform
+
+import (
+	"github.com/mitchellh/mapstructure"
+	"github.com/shopspring/decimal"
+
+	"github.com/cycloidio/terracost/aws/region"
+	"github.com/cycloidio/terracost/price"
+	"github.com/cycloidio/terracost/product"
+	"github.com/cycloidio/terracost/query"
+	"github.com/cycloidio/terracost/terraform"
+	"github.com/cycloidio/terracost/util"
+)
+
+// CloudwatchLogGroup represents an SQS queue definition that can be cost-estimated.
+type CloudwatchLogGroup struct {
+	provider *Provider
+	region   region.Code
+
+	// Usage
+	monthlyDataIngestedGB        decimal.Decimal
+	storageGB                    decimal.Decimal
+	monthlyDataScannedInsightsGB decimal.Decimal
+}
+
+type cloudwatchLogGroupValues struct {
+	Usage struct {
+		MonthlyDataIngestedGB        float64 `mapstructure:"monthly_data_ingested_gb"`
+		StorageGB                    float64 `mapstructure:"storage_gb"`
+		MonthlyDataScannedInsightsGB float64 `mapstructure:"monthly_data_scanned_insights_gb"`
+	} `mapstructure:"tc_usage"`
+}
+
+// decodeCloudwatchLogGroupValues decodes and returns cloudwatchLogGroupValues from a Terraform values map.
+func decodeCloudwatchLogGroupValues(tfVals map[string]interface{}) (cloudwatchLogGroupValues, error) {
+	var v cloudwatchLogGroupValues
+	config := &mapstructure.DecoderConfig{
+		WeaklyTypedInput: true,
+		Result:           &v,
+	}
+
+	decoder, err := mapstructure.NewDecoder(config)
+	if err != nil {
+		return v, err
+	}
+
+	if err := decoder.Decode(tfVals); err != nil {
+		return v, err
+	}
+	return v, nil
+}
+
+// newCloudwatchLogGroup creates a new CloudwatchLogGroup from cloudwatchLogGroupValues.
+func (p *Provider) newCloudwatchLogGroup(_ map[string]terraform.Resource, vals cloudwatchLogGroupValues) *CloudwatchLogGroup {
+	v := &CloudwatchLogGroup{
+		provider: p,
+		region:   p.region,
+
+		// From Usage
+		monthlyDataIngestedGB:        decimal.NewFromFloat(vals.Usage.MonthlyDataIngestedGB),
+		storageGB:                    decimal.NewFromFloat(vals.Usage.StorageGB),
+		monthlyDataScannedInsightsGB: decimal.NewFromFloat(vals.Usage.MonthlyDataScannedInsightsGB),
+	}
+
+	return v
+}
+
+// Components returns the price component queries that make up the CloudwatchLogGroup.
+func (v *CloudwatchLogGroup) Components() []query.Component {
+	components := []query.Component{v.cloudwatchLogGroupComponent()}
+	components = append(components, v.cloudwatchLogGroupArchivalStorageComponent())
+	components = append(components, v.cloudwatchLogGroupInsightsScannedComponent())
+	return components
+}
+
+func (v *CloudwatchLogGroup) cloudwatchLogGroupComponent() query.Component {
+	return query.Component{
+		Name:            "Data ingested",
+		MonthlyQuantity: v.monthlyDataIngestedGB,
+		Details:         []string{"Data ingested"},
+		Usage:           true,
+		Unit:            "GB",
+		ProductFilter: &product.Filter{
+			Provider: util.StringPtr(v.provider.key),
+			Service:  util.StringPtr("AmazonCloudWatch"),
+			Family:   util.StringPtr("Data Payload"),
+			Location: util.StringPtr(v.region.String()),
+			AttributeFilters: []*product.AttributeFilter{
+				{Key: "UsageType", ValueRegex: util.StringPtr(".*-DataProcessing-Bytes")},
+			},
+		},
+		PriceFilter: &price.Filter{
+			Unit: util.StringPtr("GB"),
+			AttributeFilters: []*price.AttributeFilter{
+				{Key: "TermType", Value: util.StringPtr("OnDemand")},
+				{Key: "StartingRange", Value: util.StringPtr("0")},
+			},
+		},
+	}
+}
+
+func (v *CloudwatchLogGroup) cloudwatchLogGroupArchivalStorageComponent() query.Component {
+	return query.Component{
+		Name:            "Archival Storage",
+		MonthlyQuantity: v.storageGB,
+		Details:         []string{"Archival Storage"},
+		Usage:           true,
+		Unit:            "GB-Mo",
+		ProductFilter: &product.Filter{
+			Provider: util.StringPtr(v.provider.key),
+			Service:  util.StringPtr("AmazonCloudWatch"),
+			Family:   util.StringPtr("Storage Snapshot"),
+			Location: util.StringPtr(v.region.String()),
+			AttributeFilters: []*product.AttributeFilter{
+				{Key: "UsageType", ValueRegex: util.StringPtr(".*-TimedStorage-ByteHrs")},
+			},
+		},
+		PriceFilter: &price.Filter{
+			Unit: util.StringPtr("GB-Mo"),
+			AttributeFilters: []*price.AttributeFilter{
+				{Key: "TermType", Value: util.StringPtr("OnDemand")},
+				{Key: "StartingRange", Value: util.StringPtr("0")},
+			},
+		},
+	}
+}
+
+func (v *CloudwatchLogGroup) cloudwatchLogGroupInsightsScannedComponent() query.Component {
+	return query.Component{
+		Name:            "Insights queries data scanned",
+		MonthlyQuantity: v.monthlyDataScannedInsightsGB,
+		Details:         []string{"Insights queries", "data scanned", "Storage"},
+		Usage:           true,
+		Unit:            "GB",
+		ProductFilter: &product.Filter{
+			Provider: util.StringPtr(v.provider.key),
+			Service:  util.StringPtr("AmazonCloudWatch"),
+			Family:   util.StringPtr("Data Payload"),
+			Location: util.StringPtr(v.region.String()),
+			AttributeFilters: []*product.AttributeFilter{
+				{Key: "UsageType", ValueRegex: util.StringPtr(".*-DataScanned-Bytes")},
+			},
+		},
+		PriceFilter: &price.Filter{
+			Unit: util.StringPtr("GB"),
+			AttributeFilters: []*price.AttributeFilter{
+				{Key: "TermType", Value: util.StringPtr("OnDemand")},
+				{Key: "StartingRange", Value: util.StringPtr("0")},
+			},
+		},
+	}
+}
diff --git a/aws/terraform/cloudwatch_metric_alarm.go b/aws/terraform/cloudwatch_metric_alarm.go
new file mode 100644
index 0000000..dfc755e
--- /dev/null
+++ b/aws/terraform/cloudwatch_metric_alarm.go
@@ -0,0 +1,142 @@
+package terraform
+
+import (
+	"fmt"
+
+	"github.com/mitchellh/mapstructure"
+	"github.com/shopspring/decimal"
+
+	"github.com/cycloidio/terracost/aws/region"
+	"github.com/cycloidio/terracost/price"
+	"github.com/cycloidio/terracost/product"
+	"github.com/cycloidio/terracost/query"
+	"github.com/cycloidio/terracost/terraform"
+	"github.com/cycloidio/terracost/util"
+)
+
+// CloudwatchMetricAlarm represents an SQS queue definition that can be cost-estimated.
+type CloudwatchMetricAlarm struct {
+	provider           *Provider
+	region             region.Code
+	comparisonOperator string
+	metricsCount       decimal.Decimal
+	period             decimal.Decimal
+}
+
+type cloudwatchMetricAlarmValues struct {
+	ComparisonOperator string  `mapstructure:"comparison_operator"`
+	Period             float64 `mapstructure:"period"`
+	MetricQuery        []struct {
+		Metric []struct {
+			Period float64 `mapstructure:"period"`
+		} `mapstructure:"metric"`
+	} `mapstructure:"metric_query"`
+}
+
+// decodeCloudwatchMetricAlarmValues decodes and returns cloudwatchMetricAlarmValues from a Terraform values map.
+func decodeCloudwatchMetricAlarmValues(tfVals map[string]interface{}) (cloudwatchMetricAlarmValues, error) {
+	var v cloudwatchMetricAlarmValues
+	config := &mapstructure.DecoderConfig{
+		WeaklyTypedInput: true,
+		Result:           &v,
+	}
+
+	decoder, err := mapstructure.NewDecoder(config)
+	if err != nil {
+		return v, err
+	}
+
+	if err := decoder.Decode(tfVals); err != nil {
+		return v, err
+	}
+	return v, nil
+}
+
+// newCloudwatchMetricAlarm creates a new CloudwatchMetricAlarm from cloudwatchMetricAlarmValues.
+func (p *Provider) newCloudwatchMetricAlarm(_ map[string]terraform.Resource, vals cloudwatchMetricAlarmValues) *CloudwatchMetricAlarm {
+	v := &CloudwatchMetricAlarm{
+		provider:           p,
+		region:             p.region,
+		comparisonOperator: vals.ComparisonOperator,
+		metricsCount:       decimal.NewFromFloat(1),
+		period:             decimal.NewFromFloat(60),
+	}
+
+	if vals.Period > 0 {
+		v.period = decimal.NewFromFloat(vals.Period)
+	}
+
+	if len(vals.MetricQuery) > 0 {
+		metricCount := 0
+		for _, metricQuery := range vals.MetricQuery {
+			if len(metricQuery.Metric) > 0 {
+				for _, metric := range metricQuery.Metric {
+					if metric.Period > 0 {
+						// if a period is defined, take the highest to estimate
+						if v.period.Cmp(decimal.NewFromFloat(metric.Period)) < 0 {
+							v.period = decimal.NewFromFloat(metric.Period)
+						}
+					}
+					metricCount++
+				}
+			}
+		}
+
+		if metricCount > 0 {
+			v.metricsCount = decimal.NewFromInt(int64(metricCount))
+		}
+	}
+
+	return v
+}
+
+// Components returns the price component queries that make up the CloudwatchMetricAlarm.
+func (v *CloudwatchMetricAlarm) Components() []query.Component {
+	components := []query.Component{v.cloudwatchMetricAlarmComponent()}
+	return components
+}
+
+func (v *CloudwatchMetricAlarm) cloudwatchMetricAlarmComponent() query.Component {
+	quantity := v.metricsCount
+	unit := "alarm metrics"
+	anomalyDetection := ""
+	alarmType := "Standard"
+	alarmName := fmt.Sprintf("%s%s", "Standard resolution", anomalyDetection)
+
+	switch v.comparisonOperator {
+	case "LessThanLowerOrGreaterThanUpperThreshold", "LessThanLowerThreshold", "GreaterThanUpperThreshold":
+		quantity = quantity.Mul(decimal.NewFromInt(3))
+		unit = "Alarms"
+		anomalyDetection = " anomaly detection"
+	}
+
+	if v.period.Div(decimal.NewFromInt(60)).LessThan(decimal.NewFromInt(1)) {
+		alarmName = fmt.Sprintf("%s%s", "High resolution", anomalyDetection)
+		alarmType = "High Resolution"
+	}
+
+	return query.Component{
+		Name:            alarmName,
+		MonthlyQuantity: quantity,
+		Details:         []string{alarmName, alarmType},
+		Usage:           true,
+		Unit:            unit,
+		ProductFilter: &product.Filter{
+			Provider: util.StringPtr(v.provider.key),
+			Service:  util.StringPtr("AmazonCloudWatch"),
+			Family:   util.StringPtr("Alarm"),
+			Location: util.StringPtr(v.region.String()),
+			AttributeFilters: []*product.AttributeFilter{
+				{Key: "UsageType", ValueRegex: util.StringPtr(".*AlarmMonitorUsage")},
+				{Key: "AlarmType", Value: util.StringPtr(alarmType)},
+			},
+		},
+		PriceFilter: &price.Filter{
+			Unit: util.StringPtr("Alarms"),
+			AttributeFilters: []*price.AttributeFilter{
+				{Key: "TermType", Value: util.StringPtr("OnDemand")},
+				{Key: "StartingRange", Value: util.StringPtr("0")},
+			},
+		},
+	}
+}
diff --git a/aws/terraform/efs_file_system.go b/aws/terraform/efs_file_system.go
index 16bb81e..d24ec00 100644
--- a/aws/terraform/efs_file_system.go
+++ b/aws/terraform/efs_file_system.go
@@ -68,7 +68,7 @@ func decodeEFSFileSystemValues(tfVals map[string]interface{}) (efsFileSystemValu
 }
 
 // newEFSFileSystem creates a new EFSFileSystem from efsFileSystemValues.
-func (p *Provider) newEFSFileSystem(rss map[string]terraform.Resource, vals efsFileSystemValues) *EFSFileSystem {
+func (p *Provider) newEFSFileSystem(_ map[string]terraform.Resource, vals efsFileSystemValues) *EFSFileSystem {
 	v := &EFSFileSystem{
 		provider:       p,
 		region:         p.region,
@@ -166,7 +166,7 @@ func (v *EFSFileSystem) efsFileSystemComponent(usagetype string, storageGB decim
 			Family:   util.StringPtr("Storage"),
 			Location: util.StringPtr(v.region.String()),
 			AttributeFilters: []*product.AttributeFilter{
-				{Key: "UsageType", ValueRegex: util.StringPtr(fmt.Sprintf("%s", usagetype))},
+				{Key: "UsageType", ValueRegex: util.StringPtr(usagetype)},
 			},
 		},
 	}
diff --git a/aws/terraform/eks_cluster.go b/aws/terraform/eks_cluster.go
index 964e00b..f6f613e 100644
--- a/aws/terraform/eks_cluster.go
+++ b/aws/terraform/eks_cluster.go
@@ -49,7 +49,7 @@ func decodeEKSClusterValues(tfVals map[string]interface{}) (eKSClusterValues, er
 }
 
 // NewInstance creates a new Instance from Terraform values.
-func (p *Provider) newEKSCluster(vals eKSClusterValues) *EKSCluster {
+func (p *Provider) newEKSCluster(_ eKSClusterValues) *EKSCluster {
 	inst := &EKSCluster{
 		providerKey: p.key,
 		region:      p.region,
diff --git a/aws/terraform/fsx_lustre_file_system.go b/aws/terraform/fsx_lustre_file_system.go
index f980e67..2435b27 100644
--- a/aws/terraform/fsx_lustre_file_system.go
+++ b/aws/terraform/fsx_lustre_file_system.go
@@ -41,7 +41,7 @@ func decodeFSxLustreFileSystemValues(tfVals map[string]interface{}) (fsxLustreFi
 }
 
 // newFSxLustreFileSystem creates a new FSxLustreFileSystem from fsxLustreFileSystemValues.
-func (p *Provider) newFSxLustreFileSystem(rss map[string]terraform.Resource, vals fsxLustreFileSystemValues) *FSxFileSystem {
+func (p *Provider) newFSxLustreFileSystem(_ map[string]terraform.Resource, vals fsxLustreFileSystemValues) *FSxFileSystem {
 	v := &FSxFileSystem{
 		provider:           p,
 		region:             p.region,
diff --git a/aws/terraform/fsx_ontap_file_system.go b/aws/terraform/fsx_ontap_file_system.go
index 88e0c22..f38a5b9 100644
--- a/aws/terraform/fsx_ontap_file_system.go
+++ b/aws/terraform/fsx_ontap_file_system.go
@@ -62,7 +62,7 @@ func (v *FSxFileSystem) getOntapDeployOption(deploymentType string) string {
 }
 
 // newFSxOntapFileSystem creates a new FSxOntapFileSystem from fsxOntapFileSystemValues.
-func (p *Provider) newFSxOntapFileSystem(rss map[string]terraform.Resource, vals fsxOntapFileSystemValues) *FSxFileSystem {
+func (p *Provider) newFSxOntapFileSystem(_ map[string]terraform.Resource, vals fsxOntapFileSystemValues) *FSxFileSystem {
 	v := &FSxFileSystem{
 		provider:           p,
 		region:             p.region,
diff --git a/aws/terraform/fsx_openzfs_file_system.go b/aws/terraform/fsx_openzfs_file_system.go
index 0b38d0b..aee4c60 100644
--- a/aws/terraform/fsx_openzfs_file_system.go
+++ b/aws/terraform/fsx_openzfs_file_system.go
@@ -62,7 +62,7 @@ func (v *FSxFileSystem) getOpenzfsDeployOption(deploymentType string) string {
 }
 
 // newFSxOpenzfsFileSystem creates a new FSxOpenzfsFileSystem from fsxOpenzfsFileSystemValues.
-func (p *Provider) newFSxOpenzfsFileSystem(rss map[string]terraform.Resource, vals fsxOpenzfsFileSystemValues) *FSxFileSystem {
+func (p *Provider) newFSxOpenzfsFileSystem(_ map[string]terraform.Resource, vals fsxOpenzfsFileSystemValues) *FSxFileSystem {
 	v := &FSxFileSystem{
 		provider:           p,
 		region:             p.region,
diff --git a/aws/terraform/fsx_windows_file_system.go b/aws/terraform/fsx_windows_file_system.go
index d5ac7d7..643fc27 100644
--- a/aws/terraform/fsx_windows_file_system.go
+++ b/aws/terraform/fsx_windows_file_system.go
@@ -57,7 +57,7 @@ func (v *FSxFileSystem) getWindowsDeployOption(deploymentType string) string {
 }
 
 // newFSxWindowsFileSystem creates a new FSxWindowsFileSystem from fsxWindowsFileSystemValues.
-func (p *Provider) newFSxWindowsFileSystem(rss map[string]terraform.Resource, vals fsxWindowsFileSystemValues) *FSxFileSystem {
+func (p *Provider) newFSxWindowsFileSystem(_ map[string]terraform.Resource, vals fsxWindowsFileSystemValues) *FSxFileSystem {
 	v := &FSxFileSystem{
 		provider:           p,
 		region:             p.region,
diff --git a/aws/terraform/kms_key.go b/aws/terraform/kms_key.go
new file mode 100644
index 0000000..9cd75b6
--- /dev/null
+++ b/aws/terraform/kms_key.go
@@ -0,0 +1,134 @@
+package terraform
+
+import (
+	"github.com/mitchellh/mapstructure"
+	"github.com/shopspring/decimal"
+
+	"github.com/cycloidio/terracost/aws/region"
+	"github.com/cycloidio/terracost/price"
+	"github.com/cycloidio/terracost/product"
+	"github.com/cycloidio/terracost/query"
+	"github.com/cycloidio/terracost/terraform"
+	"github.com/cycloidio/terracost/util"
+)
+
+// KMSKey represents an SQS queue definition that can be cost-estimated.
+type KMSKey struct {
+	provider              *Provider
+	region                region.Code
+	customerMasterKeySpec string
+}
+
+type kmsKeyValues struct {
+	CustomerMasterKeySpec string `mapstructure:"customer_master_key_spec"`
+}
+
+// decodeKMSKeyValues decodes and returns kmsKeyValues from a Terraform values map.
+func decodeKMSKeyValues(tfVals map[string]interface{}) (kmsKeyValues, error) {
+	var v kmsKeyValues
+	config := &mapstructure.DecoderConfig{
+		WeaklyTypedInput: true,
+		Result:           &v,
+	}
+
+	decoder, err := mapstructure.NewDecoder(config)
+	if err != nil {
+		return v, err
+	}
+
+	if err := decoder.Decode(tfVals); err != nil {
+		return v, err
+	}
+	return v, nil
+}
+
+// newKMSKey creates a new KMSKey from kmsKeyValues.
+func (p *Provider) newKMSKey(_ map[string]terraform.Resource, vals kmsKeyValues) *KMSKey {
+	v := &KMSKey{
+		provider:              p,
+		region:                p.region,
+		customerMasterKeySpec: "SYMMETRIC_DEFAULT",
+	}
+
+	if vals.CustomerMasterKeySpec != "" {
+		v.customerMasterKeySpec = vals.CustomerMasterKeySpec
+	}
+
+	return v
+}
+
+// Components returns the price component queries that make up the KMSKey.
+func (v *KMSKey) Components() []query.Component {
+	components := []query.Component{v.kmsKeyComponent()}
+
+	switch v.customerMasterKeySpec {
+	case "RSA_2048":
+		components = append(components, v.kmsKeyRequestComponent("Requests (RSA 2048)", ".*KMS-Requests-Asymmetric-RSA_2048$", ""))
+	case
+		"RSA_3072",
+		"RSA_4096",
+		"ECC_NIST_P256",
+		"ECC_NIST_P384",
+		"ECC_NIST_P521",
+		"ECC_SECG_P256K1":
+		components = append(components, v.kmsKeyRequestComponent("Requests (asymmetric)", ".*KMS-Requests-Asymmetric$", ""))
+	default:
+		components = append(components, v.kmsKeyRequestComponent("Requests", ".*KMS-Requests$", "API Request"))
+		components = append(components, v.kmsKeyRequestComponent("ECC GenerateDataKeyPair requests", ".*KMS-Requests-GenerateDatakeyPair-ECC$", ""))
+		components = append(components, v.kmsKeyRequestComponent("RSA GenerateDataKeyPair requests", ".*KMS-Requests-GenerateDatakeyPair-RSA$", ""))
+	}
+
+	return components
+}
+
+func (v *KMSKey) kmsKeyComponent() query.Component {
+	return query.Component{
+		Name:            "Customer master key",
+		MonthlyQuantity: decimal.NewFromInt(1),
+		Details:         []string{"master key"},
+		Usage:           false,
+		Unit:            "Keys",
+		ProductFilter: &product.Filter{
+			Provider: util.StringPtr(v.provider.key),
+			Service:  util.StringPtr("awskms"),
+			Family:   util.StringPtr("Encryption Key"),
+			Location: util.StringPtr(v.region.String()),
+			AttributeFilters: []*product.AttributeFilter{
+				{Key: "UsageType", ValueRegex: util.StringPtr(".*KMS-Keys")},
+			},
+		},
+		PriceFilter: &price.Filter{
+			Unit: util.StringPtr("Keys"),
+			AttributeFilters: []*price.AttributeFilter{
+				{Key: "TermType", Value: util.StringPtr("OnDemand")},
+				{Key: "StartingRange", Value: util.StringPtr("0")},
+			},
+		},
+	}
+}
+
+func (v *KMSKey) kmsKeyRequestComponent(name string, usageType string, family string) query.Component {
+	return query.Component{
+		Name:            name,
+		MonthlyQuantity: decimal.NewFromInt(1),
+		Details:         []string{"Request"},
+		Usage:           false,
+		Unit:            "Requests",
+		ProductFilter: &product.Filter{
+			Provider: util.StringPtr(v.provider.key),
+			Service:  util.StringPtr("awskms"),
+			Family:   util.StringPtr(family),
+			Location: util.StringPtr(v.region.String()),
+			AttributeFilters: []*product.AttributeFilter{
+				{Key: "UsageType", ValueRegex: util.StringPtr(usageType)},
+			},
+		},
+		PriceFilter: &price.Filter{
+			Unit: util.StringPtr("Requests"),
+			AttributeFilters: []*price.AttributeFilter{
+				{Key: "TermType", Value: util.StringPtr("OnDemand")},
+				{Key: "StartingRange", Value: util.StringPtr("0")},
+			},
+		},
+	}
+}
diff --git a/aws/terraform/provider.go b/aws/terraform/provider.go
index 64f7f9e..d7fde6f 100644
--- a/aws/terraform/provider.go
+++ b/aws/terraform/provider.go
@@ -41,6 +41,19 @@ func (p *Provider) ResourceComponents(rss map[string]terraform.Resource, tfRes t
 			return nil
 		}
 		return p.newAutoscalingGroup(rss, vals).Components()
+	case "aws_cloudwatch_log_group":
+		vals, err := decodeCloudwatchLogGroupValues(tfRes.Values)
+		if err != nil {
+			return nil
+		}
+		return p.newCloudwatchLogGroup(rss, vals).Components()
+	case "aws_cloudwatch_metric_alarm":
+		vals, err := decodeCloudwatchMetricAlarmValues(tfRes.Values)
+		if err != nil {
+			return nil
+		}
+		return p.newCloudwatchMetricAlarm(rss, vals).Components()
+
 	case "aws_db_instance":
 		vals, err := decodeDBInstanceValues(tfRes.Values)
 		if err != nil {
@@ -117,6 +130,12 @@ func (p *Provider) ResourceComponents(rss map[string]terraform.Resource, tfRes t
 			return nil
 		}
 		return p.newFSxWindowsFileSystem(rss, vals).Components()
+	case "aws_kms_key":
+		vals, err := decodeKMSKeyValues(tfRes.Values)
+		if err != nil {
+			return nil
+		}
+		return p.newKMSKey(rss, vals).Components()
 	case "aws_lb", "aws_alb":
 		vals, err := decodeLBValues(tfRes.Values)
 		if err != nil {
@@ -129,6 +148,48 @@ func (p *Provider) ResourceComponents(rss map[string]terraform.Resource, tfRes t
 			return nil
 		}
 		return p.newNatGateway(vals).Components()
+	case "aws_rds_cluster":
+		vals, err := decodeRDSClusterValues(tfRes.Values)
+		if err != nil {
+			return nil
+		}
+		return p.newRDSCluster(rss, vals).Components()
+	case "aws_rds_cluster_instance":
+		vals, err := decodeRDSClusterInstanceValues(tfRes.Values)
+		if err != nil {
+			return nil
+		}
+		return p.newRDSClusterInstance(rss, vals).Components()
+	case "aws_s3_bucket":
+		vals, err := decodeS3BucketValues(tfRes.Values)
+		if err != nil {
+			return nil
+		}
+		return p.newS3Bucket(rss, vals).Components()
+	case "aws_s3_bucket_analytics_configuration":
+		vals, err := decodeS3BucketAnalyticsConfigurationValues(tfRes.Values)
+		if err != nil {
+			return nil
+		}
+		return p.newS3BucketAnalyticsConfiguration(rss, vals).Components()
+	case "aws_s3_bucket_inventory":
+		vals, err := decodeS3BucketInventoryValues(tfRes.Values)
+		if err != nil {
+			return nil
+		}
+		return p.newS3BucketInventory(rss, vals).Components()
+	case "aws_secretsmanager_secret":
+		vals, err := decodeSecretsmanagerSecretValues(tfRes.Values)
+		if err != nil {
+			return nil
+		}
+		return p.newSecretsmanagerSecret(rss, vals).Components()
+	case "aws_sqs_queue":
+		vals, err := decodeSQSQueueValues(tfRes.Values)
+		if err != nil {
+			return nil
+		}
+		return p.newSQSQueue(rss, vals).Components()
 	default:
 		return nil
 	}
diff --git a/aws/terraform/rds_cluster.go b/aws/terraform/rds_cluster.go
new file mode 100644
index 0000000..82e711c
--- /dev/null
+++ b/aws/terraform/rds_cluster.go
@@ -0,0 +1,355 @@
+package terraform
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/mitchellh/mapstructure"
+	"github.com/shopspring/decimal"
+
+	"github.com/cycloidio/terracost/aws/region"
+	"github.com/cycloidio/terracost/price"
+	"github.com/cycloidio/terracost/product"
+	"github.com/cycloidio/terracost/query"
+	"github.com/cycloidio/terracost/terraform"
+	"github.com/cycloidio/terracost/util"
+)
+
+// RDSCluster represents an SQS queue definition that can be cost-estimated.
+type RDSCluster struct {
+	provider              *Provider
+	region                region.Code
+	engineMode            string
+	engine                string
+	storageType           string
+	backupRetentionPeriod decimal.Decimal
+
+	isServerless      bool
+	serverlessVersion string
+
+	// Usage
+	writeRequestsPerSec       decimal.Decimal
+	readRequestsPerSec        decimal.Decimal
+	changeRecordsPerStatement decimal.Decimal
+	storageGB                 decimal.Decimal
+	averageStatementsPerHr    decimal.Decimal
+	backtrackWindowHrs        decimal.Decimal
+	snapshotExportSizeGB      decimal.Decimal
+	capacityUnitsPerHr        decimal.Decimal
+	backupSnapshotSizeGB      decimal.Decimal
+}
+
+type rdsClusterValues struct {
+	EngineMode                       string  `mapstructure:"engine_mode"`
+	Engine                           string  `mapstructure:"engine"`
+	StorageType                      string  `mapstructure:"storage_type"`
+	BackupRetentionPeriod            float64 `mapstructure:"backup_retention_period"`
+	Serverlessv2ScalingConfiguration []struct {
+		MinCapacity float64 `mapstructure:"min_capacity"`
+	} `mapstructure:"serverlessv2_scaling_configuration"`
+
+	Usage struct {
+		WriteRequestsPerSec       float64 `mapstructure:"write_requests_per_sec"`
+		ReadRequestsPerSec        float64 `mapstructure:"read_requests_per_sec"`
+		ChangeRecordsPerStatement float64 `mapstructure:"change_records_per_statement"`
+		StorageGB                 float64 `mapstructure:"storage_gb"`
+		AverageStatementsPerHr    float64 `mapstructure:"average_statements_per_hr"`
+		BacktrackWindowHrs        float64 `mapstructure:"backtrack_window_hrs"`
+		SnapshotExportSizeGB      float64 `mapstructure:"snapshot_export_size_gb"`
+		CapacityUnitsPerHr        float64 `mapstructure:"capacity_units_per_hr"`
+		BackupSnapshotSizeGB      float64 `mapstructure:"backup_snapshot_size_gb"`
+	} `mapstructure:"tc_usage"`
+}
+
+// decodeRDSClusterValues decodes and returns rdsClusterValues from a Terraform values map.
+func decodeRDSClusterValues(tfVals map[string]interface{}) (rdsClusterValues, error) {
+	var v rdsClusterValues
+	config := &mapstructure.DecoderConfig{
+		WeaklyTypedInput: true,
+		Result:           &v,
+	}
+
+	decoder, err := mapstructure.NewDecoder(config)
+	if err != nil {
+		return v, err
+	}
+
+	if err := decoder.Decode(tfVals); err != nil {
+		return v, err
+	}
+	return v, nil
+}
+
+// newRDSCluster creates a new RDSCluster from rdsClusterValues.
+func (p *Provider) newRDSCluster(_ map[string]terraform.Resource, vals rdsClusterValues) *RDSCluster {
+	v := &RDSCluster{
+		provider:              p,
+		region:                p.region,
+		engine:                vals.Engine,
+		engineMode:            "provisioned",
+		storageType:           vals.StorageType,
+		backupRetentionPeriod: decimal.NewFromFloat(1),
+
+		serverlessVersion: "v1",
+
+		// Usage
+		writeRequestsPerSec:       decimal.NewFromFloat(vals.Usage.WriteRequestsPerSec),
+		readRequestsPerSec:        decimal.NewFromFloat(vals.Usage.ReadRequestsPerSec),
+		changeRecordsPerStatement: decimal.NewFromFloat(vals.Usage.ChangeRecordsPerStatement),
+		storageGB:                 decimal.NewFromFloat(vals.Usage.StorageGB),
+		averageStatementsPerHr:    decimal.NewFromFloat(vals.Usage.AverageStatementsPerHr),
+		backtrackWindowHrs:        decimal.NewFromFloat(vals.Usage.BacktrackWindowHrs),
+		snapshotExportSizeGB:      decimal.NewFromFloat(vals.Usage.SnapshotExportSizeGB),
+		capacityUnitsPerHr:        decimal.NewFromFloat(vals.Usage.CapacityUnitsPerHr),
+		backupSnapshotSizeGB:      decimal.NewFromFloat(vals.Usage.BackupSnapshotSizeGB),
+	}
+
+	if vals.BackupRetentionPeriod > 1 {
+		v.backupRetentionPeriod = decimal.NewFromFloat(vals.BackupRetentionPeriod)
+	}
+
+	if vals.EngineMode != "" {
+		v.engineMode = vals.EngineMode
+	}
+
+	if len(vals.Serverlessv2ScalingConfiguration) > 0 {
+		v.isServerless = true
+		v.serverlessVersion = "v2"
+	} else if v.engineMode == "serverless" {
+		v.isServerless = true
+		v.serverlessVersion = "v1"
+	}
+
+	return v
+}
+
+// Components returns the price component queries that make up the RDSCluster.
+func (v *RDSCluster) Components() []query.Component {
+
+	isIOOptimized := false
+	switch v.storageType {
+	case "aurora-iopt1":
+		isIOOptimized = true
+	}
+
+	databaseEngine := "Aurora MySQL"
+	switch v.engine {
+	case "aurora", "aurora-mysql":
+		databaseEngine = "Aurora MySQL"
+	case "aurora-postgresql":
+		databaseEngine = "Aurora PostgreSQL"
+	}
+
+	components := v.rdsClusterAuroraStorageComponent(databaseEngine, isIOOptimized)
+
+	if v.isServerless {
+		components = append(components, v.rdsClusterAuroraServerlessComponent(databaseEngine, isIOOptimized))
+	}
+
+	if v.backupRetentionPeriod.GreaterThan(decimal.NewFromFloat(1)) {
+
+		totalBackupStorageGB := v.backupSnapshotSizeGB.Mul(v.backupRetentionPeriod).Sub(v.backupSnapshotSizeGB)
+		components = append(components, v.rdsClusterAuroraBackupComponent(totalBackupStorageGB, databaseEngine))
+	}
+
+	if !v.isServerless && !strings.Contains(v.engine, "postgresql") {
+		totalBacktrackChangeRecords := v.averageStatementsPerHr.Mul(decimal.NewFromInt(730)).Mul(v.changeRecordsPerStatement).Mul(v.backtrackWindowHrs)
+		components = append(components, v.rdsClusterAuroraBacktrackComponent(totalBacktrackChangeRecords))
+	}
+
+	components = append(components, v.rdsClusterAuroraSnapshotExportComponent(databaseEngine))
+	return components
+}
+
+func (v *RDSCluster) rdsClusterAuroraServerlessComponent(databaseEngine string, isIOOptimized bool) query.Component {
+
+	family := "Serverless"
+	usageType := ".*Aurora:ServerlessUsage$"
+
+	if v.serverlessVersion == "v2" {
+		family = "ServerlessV2"
+		usageType = ".*Aurora:ServerlessV2Usage$"
+		if isIOOptimized {
+			usageType = ".*Aurora:ServerlessV2IOOptimizedUsage$"
+		}
+	}
+
+	return query.Component{
+		Name:            fmt.Sprintf("Aurora %s", family),
+		MonthlyQuantity: v.capacityUnitsPerHr,
+		Details:         []string{databaseEngine},
+		Usage:           true,
+		Unit:            "ACU-Hr",
+		ProductFilter: &product.Filter{
+			Provider: util.StringPtr(v.provider.key),
+			Service:  util.StringPtr("AmazonRDS"),
+			Family:   util.StringPtr(family),
+			Location: util.StringPtr(v.region.String()),
+			AttributeFilters: []*product.AttributeFilter{
+				{Key: "DatabaseEngine", Value: util.StringPtr(databaseEngine)},
+				{Key: "UsageType", ValueRegex: util.StringPtr(usageType)},
+			},
+		},
+		PriceFilter: &price.Filter{
+			Unit: util.StringPtr("ACU-Hr"),
+			AttributeFilters: []*price.AttributeFilter{
+				{Key: "TermType", Value: util.StringPtr("OnDemand")},
+				{Key: "StartingRange", Value: util.StringPtr("0")},
+			},
+		},
+	}
+}
+
+func (v *RDSCluster) rdsClusterAuroraStorageComponent(databaseEngine string, isIOOptimized bool) []query.Component {
+
+	name := "Storage"
+	usageType := ".*Aurora:StorageUsage$"
+	requestDatabaseEngineStorageType := databaseEngine
+
+	if isIOOptimized {
+		name = "Storage (I/O-optimized)"
+		usageType = ".*Aurora:IO-OptimizedStorageUsage$"
+	} else {
+		if databaseEngine != "Aurora PostgreSQL" {
+			databaseEngine = "Any"
+		}
+	}
+
+	if databaseEngine != "Aurora PostgreSQL" {
+		requestDatabaseEngineStorageType = "Any"
+	}
+
+	ioPerSecond := v.writeRequestsPerSec.Add(v.readRequestsPerSec)
+	monthlyIORequests := ioPerSecond.Mul(decimal.NewFromInt(730)).Mul(decimal.NewFromInt(60)).Mul(decimal.NewFromInt(60))
+	return []query.Component{
+		{
+			Name:            name,
+			MonthlyQuantity: v.storageGB,
+			Details:         []string{name},
+			Usage:           true,
+			Unit:            "GB-Mo",
+			ProductFilter: &product.Filter{
+				Provider: util.StringPtr(v.provider.key),
+				Service:  util.StringPtr("AmazonRDS"),
+				Family:   util.StringPtr("Database Storage"),
+				Location: util.StringPtr(v.region.String()),
+				AttributeFilters: []*product.AttributeFilter{
+					{Key: "DatabaseEngine", ValueRegex: util.StringPtr(databaseEngine)},
+					{Key: "UsageType", ValueRegex: util.StringPtr(usageType)},
+				},
+			},
+			PriceFilter: &price.Filter{
+				Unit: util.StringPtr("GB-Mo"),
+				AttributeFilters: []*price.AttributeFilter{
+					{Key: "TermType", Value: util.StringPtr("OnDemand")},
+					{Key: "StartingRange", Value: util.StringPtr("0")},
+				},
+			},
+		},
+		{
+			Name:            "I/O requests",
+			MonthlyQuantity: monthlyIORequests,
+			Details:         []string{"I/O requests"},
+			Usage:           true,
+			Unit:            "IOs",
+			ProductFilter: &product.Filter{
+				Provider: util.StringPtr(v.provider.key),
+				Service:  util.StringPtr("AmazonRDS"),
+				Family:   util.StringPtr("System Operation"),
+				Location: util.StringPtr(v.region.String()),
+				AttributeFilters: []*product.AttributeFilter{
+					{Key: "DatabaseEngine", ValueRegex: util.StringPtr(requestDatabaseEngineStorageType)},
+					{Key: "UsageType", ValueRegex: util.StringPtr(".*Aurora:StorageIOUsage$")},
+				},
+			},
+			PriceFilter: &price.Filter{
+				Unit: util.StringPtr("IOs"),
+				AttributeFilters: []*price.AttributeFilter{
+					{Key: "TermType", Value: util.StringPtr("OnDemand")},
+					{Key: "StartingRange", Value: util.StringPtr("0")},
+				},
+			},
+		},
+	}
+}
+
+func (v *RDSCluster) rdsClusterAuroraBackupComponent(totalBackupStorageGB decimal.Decimal, databaseEngine string) query.Component {
+
+	return query.Component{
+		Name:            "Backup storage",
+		MonthlyQuantity: totalBackupStorageGB,
+		Details:         []string{databaseEngine},
+		Usage:           true,
+		Unit:            "GB-Mo",
+		ProductFilter: &product.Filter{
+			Provider: util.StringPtr(v.provider.key),
+			Service:  util.StringPtr("AmazonRDS"),
+			Family:   util.StringPtr("Storage Snapshot"),
+			Location: util.StringPtr(v.region.String()),
+			AttributeFilters: []*product.AttributeFilter{
+				{Key: "DatabaseEngine", Value: util.StringPtr(databaseEngine)},
+				{Key: "UsageType", ValueRegex: util.StringPtr(".*Aurora:BackupUsage$")},
+			},
+		},
+		PriceFilter: &price.Filter{
+			Unit: util.StringPtr("GB-Mo"),
+			AttributeFilters: []*price.AttributeFilter{
+				{Key: "TermType", Value: util.StringPtr("OnDemand")},
+				{Key: "StartingRange", Value: util.StringPtr("0")},
+			},
+		},
+	}
+}
+
+func (v *RDSCluster) rdsClusterAuroraBacktrackComponent(totalBacktrackChangeRecords decimal.Decimal) query.Component {
+	return query.Component{
+		Name:            "Backtrack",
+		MonthlyQuantity: totalBacktrackChangeRecords,
+		Details:         []string{"Backtrack"},
+		Usage:           true,
+		Unit:            "CR-Hr",
+		ProductFilter: &product.Filter{
+			Provider: util.StringPtr(v.provider.key),
+			Service:  util.StringPtr("AmazonRDS"),
+			Family:   util.StringPtr("System Operation"),
+			Location: util.StringPtr(v.region.String()),
+			AttributeFilters: []*product.AttributeFilter{
+				{Key: "UsageType", ValueRegex: util.StringPtr(".*Aurora:BacktrackUsage$")},
+			},
+		},
+		PriceFilter: &price.Filter{
+			Unit: util.StringPtr("CR-Hr"),
+			AttributeFilters: []*price.AttributeFilter{
+				{Key: "TermType", Value: util.StringPtr("OnDemand")},
+				{Key: "StartingRange", Value: util.StringPtr("0")},
+			},
+		},
+	}
+}
+
+func (v *RDSCluster) rdsClusterAuroraSnapshotExportComponent(databaseEngine string) query.Component {
+	return query.Component{
+		Name:            "Snapshot export",
+		MonthlyQuantity: v.snapshotExportSizeGB,
+		Details:         []string{"Snapshot"},
+		Usage:           true,
+		Unit:            "GB",
+		ProductFilter: &product.Filter{
+			Provider: util.StringPtr(v.provider.key),
+			Service:  util.StringPtr("AmazonRDS"),
+			Family:   util.StringPtr("System Operation"),
+			Location: util.StringPtr(v.region.String()),
+			AttributeFilters: []*product.AttributeFilter{
+				{Key: "DatabaseEngine", Value: util.StringPtr(databaseEngine)},
+				{Key: "UsageType", ValueRegex: util.StringPtr(".*Aurora:SnapshotExportToS3$")},
+			},
+		},
+		PriceFilter: &price.Filter{
+			Unit: util.StringPtr("GB"),
+			AttributeFilters: []*price.AttributeFilter{
+				{Key: "TermType", Value: util.StringPtr("OnDemand")},
+				{Key: "StartingRange", Value: util.StringPtr("0")},
+			},
+		},
+	}
+}
diff --git a/aws/terraform/rds_cluster_instance.go b/aws/terraform/rds_cluster_instance.go
new file mode 100644
index 0000000..152144a
--- /dev/null
+++ b/aws/terraform/rds_cluster_instance.go
@@ -0,0 +1,247 @@
+package terraform
+
+import (
+	"strings"
+
+	"github.com/mitchellh/mapstructure"
+	"github.com/shopspring/decimal"
+
+	"github.com/cycloidio/terracost/aws/region"
+	"github.com/cycloidio/terracost/price"
+	"github.com/cycloidio/terracost/product"
+	"github.com/cycloidio/terracost/query"
+	"github.com/cycloidio/terracost/terraform"
+	"github.com/cycloidio/terracost/util"
+)
+
+// RDSClusterInstance represents an SQS queue definition that can be cost-estimated.
+type RDSClusterInstance struct {
+	provider                           *Provider
+	region                             region.Code
+	engine                             string
+	engineVersion                      string
+	instanceClass                      string
+	storageType                        string
+	performanceInsightsEnabled         bool
+	performanceInsightsRetentionPeriod decimal.Decimal
+
+	isServerless  bool
+	isIOOptimized bool
+
+	// Usage
+	monthlyAdditionalPerformanceInsightsRequests decimal.Decimal
+	capacityUnitsPerHr                           decimal.Decimal
+}
+
+type rdsClusterInstanceValues struct {
+	ClusterIdentifier string `mapstructure:"cluster_identifier"`
+
+	InstanceClass string `mapstructure:"instance_class"`
+	StorageType   string `mapstructure:"storage_type"`
+
+	Engine        string `mapstructure:"engine"`
+	EngineVersion string `mapstructure:"engine_version"`
+
+	PerformanceInsightsEnabled         bool    `mapstructure:"performance_insights_enabled"`
+	PerformanceInsightsRetentionPeriod float64 `mapstructure:"performance_insights_retention_period"` // Long retention > 7
+
+	Usage struct {
+		MonthlyAdditionalPerformanceInsightsRequests float64 `mapstructure:"monthly_additional_performance_insights_requests"`
+		CapacityUnitsPerHr                           float64 `mapstructure:"capacity_units_per_hr"`
+	} `mapstructure:"tc_usage"`
+}
+
+// decodeRDSClusterInstanceValues decodes and returns rdsClusterInstanceValues from a Terraform values map.
+func decodeRDSClusterInstanceValues(tfVals map[string]interface{}) (rdsClusterInstanceValues, error) {
+	var v rdsClusterInstanceValues
+	config := &mapstructure.DecoderConfig{
+		WeaklyTypedInput: true,
+		Result:           &v,
+	}
+
+	decoder, err := mapstructure.NewDecoder(config)
+	if err != nil {
+		return v, err
+	}
+
+	if err := decoder.Decode(tfVals); err != nil {
+		return v, err
+	}
+	return v, nil
+}
+
+// newRDSClusterInstance creates a new RDSClusterInstance from rdsClusterInstanceValues.
+func (p *Provider) newRDSClusterInstance(_ map[string]terraform.Resource, vals rdsClusterInstanceValues) *RDSClusterInstance {
+	v := &RDSClusterInstance{
+		provider:                           p,
+		region:                             p.region,
+		isIOOptimized:                      false,
+		instanceClass:                      vals.InstanceClass,
+		performanceInsightsEnabled:         vals.PerformanceInsightsEnabled,
+		performanceInsightsRetentionPeriod: decimal.NewFromFloat(vals.PerformanceInsightsRetentionPeriod),
+		engine:                             vals.Engine,
+		engineVersion:                      vals.EngineVersion,
+
+		// Usage
+		capacityUnitsPerHr:                           decimal.NewFromFloat(vals.Usage.CapacityUnitsPerHr),
+		monthlyAdditionalPerformanceInsightsRequests: decimal.NewFromFloat(vals.Usage.MonthlyAdditionalPerformanceInsightsRequests),
+	}
+
+	v.isServerless = strings.EqualFold(vals.InstanceClass, "db.serverless")
+
+	switch v.storageType {
+	case "aurora-iopt1":
+		v.isIOOptimized = true
+	}
+
+	return v
+}
+
+// Components returns the price component queries that make up the RDSClusterInstance.
+func (v *RDSClusterInstance) Components() []query.Component {
+	components := []query.Component{}
+
+	databaseEngine := "Aurora MySQL"
+	if v.engine == "aurora-postgresql" {
+		databaseEngine = "Aurora PostgreSQL"
+	}
+
+	if v.isServerless {
+		components = append(components, v.rdsClusterInstanceServerlessV2CostComponent(databaseEngine))
+	} else {
+		components = append(components, v.rdsClusterInstanceCostComponent(databaseEngine))
+	}
+
+	if v.performanceInsightsEnabled {
+
+		if v.performanceInsightsRetentionPeriod.Cmp(decimal.NewFromInt(7)) > 0 {
+			components = append(components, v.rdsClusterInstanceInsightsLongTermRetentionComponent(databaseEngine))
+		}
+
+		components = append(components, v.rdsClusterInstanceInsightsAPIRequestComponent())
+	}
+	return components
+}
+
+func (v *RDSClusterInstance) rdsClusterInstanceServerlessV2CostComponent(databaseEngine string) query.Component {
+
+	name := "Aurora serverless v2"
+	usageType := ".*Aurora:ServerlessV2Usage$"
+	if v.isIOOptimized {
+		name = "Aurora serverless v2 (I/O-optimized)"
+		usageType = ".*Aurora:ServerlessV2IOOptimizedUsage$"
+	}
+
+	return query.Component{
+		Name:           name,
+		HourlyQuantity: v.capacityUnitsPerHr,
+		Details:        []string{name},
+		Usage:          true,
+		Unit:           "ACU-Hr",
+		ProductFilter: &product.Filter{
+			Provider: util.StringPtr(v.provider.key),
+			Service:  util.StringPtr("AmazonRDS"),
+			Family:   util.StringPtr("ServerlessV2"),
+			Location: util.StringPtr(v.region.String()),
+			AttributeFilters: []*product.AttributeFilter{
+				{Key: "DatabaseEngine", Value: util.StringPtr(databaseEngine)},
+				{Key: "UsageType", ValueRegex: util.StringPtr(usageType)},
+			},
+		},
+		PriceFilter: &price.Filter{
+			Unit: util.StringPtr("ACU-Hr"),
+			AttributeFilters: []*price.AttributeFilter{
+				{Key: "TermType", Value: util.StringPtr("OnDemand")},
+				{Key: "StartingRange", Value: util.StringPtr("0")},
+			},
+		},
+	}
+}
+
+func (v *RDSClusterInstance) rdsClusterInstanceCostComponent(databaseEngine string) query.Component {
+
+	usageType := ".*InstanceUsage:.*"
+	if v.isIOOptimized {
+		usageType = ".*InstanceUsageIOOptimized:.*"
+	}
+
+	return query.Component{
+		Name:           "Database instance",
+		HourlyQuantity: decimal.NewFromInt(1),
+		Details:        []string{"instance"},
+		Usage:          false,
+		Unit:           "Hrs",
+		ProductFilter: &product.Filter{
+			Provider: util.StringPtr(v.provider.key),
+			Service:  util.StringPtr("AmazonRDS"),
+			Family:   util.StringPtr("Database Instance"),
+			Location: util.StringPtr(v.region.String()),
+			AttributeFilters: []*product.AttributeFilter{
+				{Key: "InstanceType", Value: util.StringPtr(v.instanceClass)},
+				{Key: "DatabaseEngine", Value: util.StringPtr(databaseEngine)},
+				{Key: "UsageType", ValueRegex: util.StringPtr(usageType)},
+			},
+		},
+		PriceFilter: &price.Filter{
+			Unit: util.StringPtr("Hrs"),
+			AttributeFilters: []*price.AttributeFilter{
+				{Key: "TermType", Value: util.StringPtr("OnDemand")},
+				{Key: "StartingRange", Value: util.StringPtr("0")},
+			},
+		},
+	}
+}
+
+func (v *RDSClusterInstance) rdsClusterInstanceInsightsLongTermRetentionComponent(databaseEngine string) query.Component {
+
+	return query.Component{
+		Name:            "Performance Insights Long Term Retention (serverless)",
+		MonthlyQuantity: v.capacityUnitsPerHr,
+		Details:         []string{"Insights"},
+		Usage:           true,
+		Unit:            "ACU-Months",
+		ProductFilter: &product.Filter{
+			Provider: util.StringPtr(v.provider.key),
+			Service:  util.StringPtr("AmazonRDS"),
+			Family:   util.StringPtr("Performance Insights"),
+			Location: util.StringPtr(v.region.String()),
+			AttributeFilters: []*product.AttributeFilter{
+				{Key: "DatabaseEngine", Value: util.StringPtr(databaseEngine)},
+				{Key: "UsageType", ValueRegex: util.StringPtr(".*PI_LTR_FMR:Serverless$")},
+			},
+		},
+		PriceFilter: &price.Filter{
+			Unit: util.StringPtr("ACU-Months"),
+			AttributeFilters: []*price.AttributeFilter{
+				{Key: "TermType", Value: util.StringPtr("OnDemand")},
+				{Key: "StartingRange", Value: util.StringPtr("0")},
+			},
+		},
+	}
+}
+
+func (v *RDSClusterInstance) rdsClusterInstanceInsightsAPIRequestComponent() query.Component {
+	return query.Component{
+		Name:            "Performance Insights API",
+		MonthlyQuantity: v.monthlyAdditionalPerformanceInsightsRequests,
+		Details:         []string{"Requests"},
+		Usage:           true,
+		Unit:            "API Calls",
+		ProductFilter: &product.Filter{
+			Provider: util.StringPtr(v.provider.key),
+			Service:  util.StringPtr("AmazonRDS"),
+			Family:   util.StringPtr("Performance Insights"),
+			Location: util.StringPtr(v.region.String()),
+			AttributeFilters: []*product.AttributeFilter{
+				{Key: "UsageType", ValueRegex: util.StringPtr(".*PI_API$")},
+			},
+		},
+		PriceFilter: &price.Filter{
+			Unit: util.StringPtr("API Calls"),
+			AttributeFilters: []*price.AttributeFilter{
+				{Key: "TermType", Value: util.StringPtr("OnDemand")},
+				{Key: "StartingRange", Value: util.StringPtr("0")},
+			},
+		},
+	}
+}
diff --git a/aws/terraform/s3_bucket.go b/aws/terraform/s3_bucket.go
new file mode 100644
index 0000000..8c71c2a
--- /dev/null
+++ b/aws/terraform/s3_bucket.go
@@ -0,0 +1,167 @@
+package terraform
+
+import (
+	"fmt"
+
+	"github.com/mitchellh/mapstructure"
+	"github.com/shopspring/decimal"
+
+	"github.com/cycloidio/terracost/aws/region"
+	"github.com/cycloidio/terracost/price"
+	"github.com/cycloidio/terracost/product"
+	"github.com/cycloidio/terracost/query"
+	"github.com/cycloidio/terracost/terraform"
+	"github.com/cycloidio/terracost/util"
+)
+
+// S3Bucket represents an SQS queue definition that can be cost-estimated.
+type S3Bucket struct {
+	provider *Provider
+	region   region.Code
+
+	// Usage
+	monthlyOutboundDataGB decimal.Decimal
+	storageGB             decimal.Decimal
+}
+
+type s3BucketValues struct {
+
+	// Usage
+	Usage struct {
+		MonthlyOutboundDataGB float64 `mapstructure:"monthly_outbound_data_gb"`
+		StorageGB             float64 `mapstructure:"storage_gb"`
+	} `mapstructure:"tc_usage"`
+}
+
+// decodeS3BucketValues decodes and returns S3BucketValues from a Terraform values map.
+func decodeS3BucketValues(tfVals map[string]interface{}) (s3BucketValues, error) {
+	var v s3BucketValues
+	config := &mapstructure.DecoderConfig{
+		WeaklyTypedInput: true,
+		Result:           &v,
+	}
+
+	decoder, err := mapstructure.NewDecoder(config)
+	if err != nil {
+		return v, err
+	}
+
+	if err := decoder.Decode(tfVals); err != nil {
+		return v, err
+	}
+	return v, nil
+}
+
+// newS3Bucket creates a new S3Bucket from s3BucketValues.
+func (p *Provider) newS3Bucket(_ map[string]terraform.Resource, vals s3BucketValues) *S3Bucket {
+	v := &S3Bucket{
+		provider: p,
+		region:   p.region,
+
+		// From Usage
+		monthlyOutboundDataGB: decimal.NewFromFloat(vals.Usage.MonthlyOutboundDataGB),
+		storageGB:             decimal.NewFromFloat(vals.Usage.StorageGB),
+	}
+
+	return v
+}
+
+// Components returns the price component queries that make up the S3Bucket.
+func (v *S3Bucket) Components() []query.Component {
+	components := []query.Component{}
+
+	if v.storageGB.GreaterThan(decimal.NewFromInt(512000)) {
+		extraSize := v.storageGB.Sub(decimal.NewFromInt(512000))
+		components = append(components, v.S3BucketComponent("0", decimal.NewFromInt(51200)))
+		components = append(components, v.S3BucketComponent("51200", decimal.NewFromInt(460800)))
+		components = append(components, v.S3BucketComponent("512000", extraSize))
+
+	} else if v.storageGB.GreaterThan(decimal.NewFromInt(51200)) {
+		extraSize := v.storageGB.Sub(decimal.NewFromInt(51200))
+		components = append(components, v.S3BucketComponent("0", decimal.NewFromInt(51200)))
+		components = append(components, v.S3BucketComponent("51200", extraSize))
+	} else {
+		components = append(components, v.S3BucketComponent("0", v.storageGB))
+	}
+
+	if v.monthlyOutboundDataGB.GreaterThan(decimal.NewFromInt(153600)) {
+		extraOut := v.monthlyOutboundDataGB.Sub(decimal.NewFromInt(153600))
+		components = append(components, v.S3BucketOutboundDataTransferComponent("0", decimal.NewFromInt(10240)))
+		components = append(components, v.S3BucketOutboundDataTransferComponent("10240", decimal.NewFromInt(40960)))
+		components = append(components, v.S3BucketOutboundDataTransferComponent("51200", decimal.NewFromInt(102400)))
+		components = append(components, v.S3BucketOutboundDataTransferComponent("153600", extraOut))
+	} else if v.monthlyOutboundDataGB.GreaterThan(decimal.NewFromInt(51200)) {
+		extraOut := v.monthlyOutboundDataGB.Sub(decimal.NewFromInt(51200))
+		components = append(components, v.S3BucketOutboundDataTransferComponent("0", decimal.NewFromInt(51200)))
+		components = append(components, v.S3BucketOutboundDataTransferComponent("10240", decimal.NewFromInt(40960)))
+		components = append(components, v.S3BucketOutboundDataTransferComponent("51200", extraOut))
+	} else if v.monthlyOutboundDataGB.GreaterThan(decimal.NewFromInt(10240)) {
+		extraOut := v.monthlyOutboundDataGB.Sub(decimal.NewFromInt(10240))
+		components = append(components, v.S3BucketOutboundDataTransferComponent("0", decimal.NewFromInt(51200)))
+		components = append(components, v.S3BucketOutboundDataTransferComponent("10240", extraOut))
+	} else {
+		components = append(components, v.S3BucketOutboundDataTransferComponent("0", v.monthlyOutboundDataGB))
+	}
+
+	return components
+}
+
+func (v *S3Bucket) S3BucketComponent(startingRange string, storage decimal.Decimal) query.Component {
+	return query.Component{
+		Name:            fmt.Sprintf("Storage %s", startingRange),
+		MonthlyQuantity: storage,
+		Details:         []string{"Standard"},
+		Usage:           true,
+		Unit:            "GB-Mo",
+		ProductFilter: &product.Filter{
+			Provider: util.StringPtr(v.provider.key),
+			Service:  util.StringPtr("AmazonS3"),
+			Family:   util.StringPtr("Storage"),
+			Location: util.StringPtr(v.region.String()),
+			AttributeFilters: []*product.AttributeFilter{
+				{Key: "UsageType", ValueRegex: util.StringPtr(".*TimedStorage-ByteHrs$")},
+				{Key: "VolumeType", Value: util.StringPtr("Standard")},
+			},
+		},
+		PriceFilter: &price.Filter{
+			Unit: util.StringPtr("GB-Mo"),
+			AttributeFilters: []*price.AttributeFilter{
+				{Key: "TermType", Value: util.StringPtr("OnDemand")},
+				{Key: "StartingRange", Value: util.StringPtr(startingRange)},
+			},
+		},
+	}
+}
+
+func (v *S3Bucket) S3BucketOutboundDataTransferComponent(startingRange string, outboundGB decimal.Decimal) query.Component {
+	shortRegion := region.GetRegionToShortName(v.region.String())
+	usageType := "DataTransfer-Out-Bytes"
+	// us-east-1 is a special case where no shortRegion should be used
+	if shortRegion != "" && shortRegion != "us-east-1" {
+		usageType = fmt.Sprintf("%s-DataTransfer-Out-Bytes", shortRegion)
+	}
+
+	return query.Component{
+		Name:            fmt.Sprintf("Outbound Data Transfer %s", startingRange),
+		MonthlyQuantity: outboundGB,
+		Details:         []string{"Outbound"},
+		Usage:           true,
+		Unit:            "GB",
+		ProductFilter: &product.Filter{
+			Provider: util.StringPtr(v.provider.key),
+			Service:  util.StringPtr("AWSDataTransfer"),
+			Family:   util.StringPtr("Data Transfer"),
+			Location: util.StringPtr(""),
+			AttributeFilters: []*product.AttributeFilter{
+				{Key: "UsageType", Value: util.StringPtr(usageType)},
+			},
+		},
+		PriceFilter: &price.Filter{
+			Unit: util.StringPtr("GB"),
+			AttributeFilters: []*price.AttributeFilter{
+				{Key: "TermType", Value: util.StringPtr("OnDemand")},
+				{Key: "StartingRange", Value: util.StringPtr(startingRange)},
+			},
+		},
+	}
+}
diff --git a/aws/terraform/s3_bucket_analytics_configuration.go b/aws/terraform/s3_bucket_analytics_configuration.go
new file mode 100644
index 0000000..c5e996a
--- /dev/null
+++ b/aws/terraform/s3_bucket_analytics_configuration.go
@@ -0,0 +1,92 @@
+package terraform
+
+import (
+	"github.com/mitchellh/mapstructure"
+	"github.com/shopspring/decimal"
+
+	"github.com/cycloidio/terracost/aws/region"
+	"github.com/cycloidio/terracost/price"
+	"github.com/cycloidio/terracost/product"
+	"github.com/cycloidio/terracost/query"
+	"github.com/cycloidio/terracost/terraform"
+	"github.com/cycloidio/terracost/util"
+)
+
+// S3BucketAnalyticsConfiguration represents an SQS queue definition that can be cost-estimated.
+type S3BucketAnalyticsConfiguration struct {
+	provider *Provider
+	region   region.Code
+
+	// Usage
+	monthlyMonitoredObjects decimal.Decimal
+}
+
+type s3BucketAnalyticsConfigurationValues struct {
+	Usage struct {
+		MonthlyMonitoredObjects float64 `mapstructure:"monthly_monitored_objects"`
+	} `mapstructure:"tc_usage"`
+}
+
+// decodeS3BucketAnalyticsConfigurationValues decodes and returns s3BucketAnalyticsConfigurationValues from a Terraform values map.
+func decodeS3BucketAnalyticsConfigurationValues(tfVals map[string]interface{}) (s3BucketAnalyticsConfigurationValues, error) {
+	var v s3BucketAnalyticsConfigurationValues
+	config := &mapstructure.DecoderConfig{
+		WeaklyTypedInput: true,
+		Result:           &v,
+	}
+
+	decoder, err := mapstructure.NewDecoder(config)
+	if err != nil {
+		return v, err
+	}
+
+	if err := decoder.Decode(tfVals); err != nil {
+		return v, err
+	}
+	return v, nil
+}
+
+// newS3BucketAnalyticsConfiguration creates a new S3BucketAnalyticsConfiguration from s3BucketAnalyticsConfigurationValues.
+func (p *Provider) newS3BucketAnalyticsConfiguration(_ map[string]terraform.Resource, vals s3BucketAnalyticsConfigurationValues) *S3BucketAnalyticsConfiguration {
+	v := &S3BucketAnalyticsConfiguration{
+		provider: p,
+		region:   p.region,
+
+		// Usage
+		monthlyMonitoredObjects: decimal.NewFromFloat(vals.Usage.MonthlyMonitoredObjects),
+	}
+
+	return v
+}
+
+// Components returns the price component queries that make up the S3BucketAnalyticsConfiguration.
+func (v *S3BucketAnalyticsConfiguration) Components() []query.Component {
+	components := []query.Component{v.s3BucketAnalyticsConfigurationComponent()}
+	return components
+}
+
+func (v *S3BucketAnalyticsConfiguration) s3BucketAnalyticsConfigurationComponent() query.Component {
+	return query.Component{
+		Name:            "Objects monitored",
+		MonthlyQuantity: v.monthlyMonitoredObjects,
+		Details:         []string{"Monitored"},
+		Usage:           true,
+		Unit:            "Objects",
+		ProductFilter: &product.Filter{
+			Provider: util.StringPtr(v.provider.key),
+			Service:  util.StringPtr("AmazonS3"),
+			Family:   util.StringPtr("Fee"),
+			Location: util.StringPtr(v.region.String()),
+			AttributeFilters: []*product.AttributeFilter{
+				{Key: "UsageType", ValueRegex: util.StringPtr(".*StorageAnalytics-ObjCount$")},
+			},
+		},
+		PriceFilter: &price.Filter{
+			Unit: util.StringPtr("Objects"),
+			AttributeFilters: []*price.AttributeFilter{
+				{Key: "TermType", Value: util.StringPtr("OnDemand")},
+				{Key: "StartingRange", Value: util.StringPtr("0")},
+			},
+		},
+	}
+}
diff --git a/aws/terraform/s3_bucket_inventory.go b/aws/terraform/s3_bucket_inventory.go
new file mode 100644
index 0000000..307c0f6
--- /dev/null
+++ b/aws/terraform/s3_bucket_inventory.go
@@ -0,0 +1,92 @@
+package terraform
+
+import (
+	"github.com/mitchellh/mapstructure"
+	"github.com/shopspring/decimal"
+
+	"github.com/cycloidio/terracost/aws/region"
+	"github.com/cycloidio/terracost/price"
+	"github.com/cycloidio/terracost/product"
+	"github.com/cycloidio/terracost/query"
+	"github.com/cycloidio/terracost/terraform"
+	"github.com/cycloidio/terracost/util"
+)
+
+// S3BucketInventory represents an SQS queue definition that can be cost-estimated.
+type S3BucketInventory struct {
+	provider *Provider
+	region   region.Code
+
+	// Usage
+	monthlyListedObjects decimal.Decimal
+}
+
+type s3BucketInventoryValues struct {
+	Usage struct {
+		MonthlyListedObjects float64 `mapstructure:"monthly_listed_objects"`
+	} `mapstructure:"tc_usage"`
+}
+
+// decodeS3BucketInventoryValues decodes and returns s3BucketInventoryValues from a Terraform values map.
+func decodeS3BucketInventoryValues(tfVals map[string]interface{}) (s3BucketInventoryValues, error) {
+	var v s3BucketInventoryValues
+	config := &mapstructure.DecoderConfig{
+		WeaklyTypedInput: true,
+		Result:           &v,
+	}
+
+	decoder, err := mapstructure.NewDecoder(config)
+	if err != nil {
+		return v, err
+	}
+
+	if err := decoder.Decode(tfVals); err != nil {
+		return v, err
+	}
+	return v, nil
+}
+
+// newS3BucketInventory creates a new S3BucketInventory from s3BucketInventoryValues.
+func (p *Provider) newS3BucketInventory(_ map[string]terraform.Resource, vals s3BucketInventoryValues) *S3BucketInventory {
+	v := &S3BucketInventory{
+		provider: p,
+		region:   p.region,
+
+		// Usage
+		monthlyListedObjects: decimal.NewFromFloat(vals.Usage.MonthlyListedObjects),
+	}
+
+	return v
+}
+
+// Components returns the price component queries that make up the S3BucketInventory.
+func (v *S3BucketInventory) Components() []query.Component {
+	components := []query.Component{v.s3BucketInventoryComponent()}
+	return components
+}
+
+func (v *S3BucketInventory) s3BucketInventoryComponent() query.Component {
+	return query.Component{
+		Name:            "Objects listed",
+		MonthlyQuantity: v.monthlyListedObjects,
+		Details:         []string{"Listed"},
+		Usage:           true,
+		Unit:            "Objects",
+		ProductFilter: &product.Filter{
+			Provider: util.StringPtr(v.provider.key),
+			Service:  util.StringPtr("AmazonS3"),
+			Family:   util.StringPtr("Fee"),
+			Location: util.StringPtr(v.region.String()),
+			AttributeFilters: []*product.AttributeFilter{
+				{Key: "UsageType", ValueRegex: util.StringPtr(".*Inventory-ObjectsListed$")},
+			},
+		},
+		PriceFilter: &price.Filter{
+			Unit: util.StringPtr("Objects"),
+			AttributeFilters: []*price.AttributeFilter{
+				{Key: "TermType", Value: util.StringPtr("OnDemand")},
+				{Key: "StartingRange", Value: util.StringPtr("0")},
+			},
+		},
+	}
+}
diff --git a/aws/terraform/secretsmanager_secret.go b/aws/terraform/secretsmanager_secret.go
new file mode 100644
index 0000000..112ae1f
--- /dev/null
+++ b/aws/terraform/secretsmanager_secret.go
@@ -0,0 +1,119 @@
+package terraform
+
+import (
+	"github.com/mitchellh/mapstructure"
+	"github.com/shopspring/decimal"
+
+	"github.com/cycloidio/terracost/aws/region"
+	"github.com/cycloidio/terracost/price"
+	"github.com/cycloidio/terracost/product"
+	"github.com/cycloidio/terracost/query"
+	"github.com/cycloidio/terracost/terraform"
+	"github.com/cycloidio/terracost/util"
+)
+
+// SecretsmanagerSecret represents an SQS queue definition that can be cost-estimated.
+type SecretsmanagerSecret struct {
+	provider *Provider
+	region   region.Code
+
+	// Usage
+	monthlyRequests decimal.Decimal
+}
+
+type secretsmanagerSecretValues struct {
+	Usage struct {
+		MonthlyRequests float64 `mapstructure:"monthly_requests"`
+	} `mapstructure:"tc_usage"`
+}
+
+// decodeSecretsmanagerSecretValues decodes and returns secretsmanagerSecretValues from a Terraform values map.
+func decodeSecretsmanagerSecretValues(tfVals map[string]interface{}) (secretsmanagerSecretValues, error) {
+	var v secretsmanagerSecretValues
+	config := &mapstructure.DecoderConfig{
+		WeaklyTypedInput: true,
+		Result:           &v,
+	}
+
+	decoder, err := mapstructure.NewDecoder(config)
+	if err != nil {
+		return v, err
+	}
+
+	if err := decoder.Decode(tfVals); err != nil {
+		return v, err
+	}
+	return v, nil
+}
+
+// newSecretsmanagerSecret creates a new SecretsmanagerSecret from secretsmanagerSecretValues.
+func (p *Provider) newSecretsmanagerSecret(_ map[string]terraform.Resource, vals secretsmanagerSecretValues) *SecretsmanagerSecret {
+	v := &SecretsmanagerSecret{
+		provider: p,
+		region:   p.region,
+
+		// From Usage
+		monthlyRequests: decimal.NewFromFloat(vals.Usage.MonthlyRequests),
+	}
+
+	return v
+}
+
+// Components returns the price component queries that make up the SecretsmanagerSecret.
+func (v *SecretsmanagerSecret) Components() []query.Component {
+	components := []query.Component{v.secretsmanagerSecretComponent()}
+	components = append(components, v.secretsmanagerSecretRequestsComponent())
+	return components
+}
+
+func (v *SecretsmanagerSecret) secretsmanagerSecretComponent() query.Component {
+	return query.Component{
+		Name:            "Secret",
+		MonthlyQuantity: decimal.NewFromInt(1),
+		Details:         []string{"Secret"},
+		Usage:           true,
+		Unit:            "Secrets",
+		ProductFilter: &product.Filter{
+			Provider: util.StringPtr(v.provider.key),
+			Service:  util.StringPtr("AWSSecretsManager"),
+			Family:   util.StringPtr("Secret"),
+			Location: util.StringPtr(v.region.String()),
+			AttributeFilters: []*product.AttributeFilter{
+				{Key: "UsageType", ValueRegex: util.StringPtr(".*-AWSSecretsManager-Secrets")},
+			},
+		},
+		PriceFilter: &price.Filter{
+			Unit: util.StringPtr("Secrets"),
+			AttributeFilters: []*price.AttributeFilter{
+				{Key: "TermType", Value: util.StringPtr("OnDemand")},
+				{Key: "StartingRange", Value: util.StringPtr("0")},
+			},
+		},
+	}
+}
+
+func (v *SecretsmanagerSecret) secretsmanagerSecretRequestsComponent() query.Component {
+	return query.Component{
+		Name:            "API Request",
+		MonthlyQuantity: v.monthlyRequests,
+		Details:         []string{"API Request"},
+		Usage:           true,
+		Unit:            "API Requests",
+		ProductFilter: &product.Filter{
+			Provider: util.StringPtr(v.provider.key),
+			Service:  util.StringPtr("AWSSecretsManager"),
+			Family:   util.StringPtr("API Request"),
+			Location: util.StringPtr(v.region.String()),
+			AttributeFilters: []*product.AttributeFilter{
+				{Key: "UsageType", ValueRegex: util.StringPtr(".*-AWSSecretsManager[-]?APIRequest[s]?")},
+			},
+		},
+		PriceFilter: &price.Filter{
+			Unit: util.StringPtr("API Requests"),
+			AttributeFilters: []*price.AttributeFilter{
+				{Key: "TermType", Value: util.StringPtr("OnDemand")},
+				{Key: "StartingRange", Value: util.StringPtr("0")},
+			},
+		},
+	}
+}
diff --git a/aws/terraform/sqs_queue.go b/aws/terraform/sqs_queue.go
new file mode 100644
index 0000000..0740b11
--- /dev/null
+++ b/aws/terraform/sqs_queue.go
@@ -0,0 +1,111 @@
+package terraform
+
+import (
+	"fmt"
+
+	"github.com/mitchellh/mapstructure"
+	"github.com/shopspring/decimal"
+
+	"github.com/cycloidio/terracost/aws/region"
+	"github.com/cycloidio/terracost/price"
+	"github.com/cycloidio/terracost/product"
+	"github.com/cycloidio/terracost/query"
+	"github.com/cycloidio/terracost/terraform"
+	"github.com/cycloidio/terracost/util"
+)
+
+// SQSQueue represents an SQS queue definition that can be cost-estimated.
+type SQSQueue struct {
+	provider *Provider
+	region   region.Code
+
+	fifoQueue bool
+
+	// Usage
+	monthlyRequests decimal.Decimal
+	requestSizeKB   decimal.Decimal
+}
+
+type sqsQueueValues struct {
+	FifoQueue bool `mapstructure:"fifo_queue"`
+
+	Usage struct {
+		MonthlyRequests float64 `mapstructure:"monthly_requests"`
+		RequestSizeKB   float64 `mapstructure:"request_size_kb"`
+	} `mapstructure:"tc_usage"`
+}
+
+// decodeSQSQueueValues decodes and returns sqsQueueValues from a Terraform values map.
+func decodeSQSQueueValues(tfVals map[string]interface{}) (sqsQueueValues, error) {
+	var v sqsQueueValues
+	config := &mapstructure.DecoderConfig{
+		WeaklyTypedInput: true,
+		Result:           &v,
+	}
+
+	decoder, err := mapstructure.NewDecoder(config)
+	if err != nil {
+		return v, err
+	}
+
+	if err := decoder.Decode(tfVals); err != nil {
+		return v, err
+	}
+	return v, nil
+}
+
+// newSQSQueue creates a new SQSQueue from sqsQueueValues.
+func (p *Provider) newSQSQueue(_ map[string]terraform.Resource, vals sqsQueueValues) *SQSQueue {
+	v := &SQSQueue{
+		provider:  p,
+		region:    p.region,
+		fifoQueue: vals.FifoQueue,
+
+		// From Usage
+		monthlyRequests: decimal.NewFromFloat(vals.Usage.MonthlyRequests),
+		requestSizeKB:   decimal.NewFromFloat(vals.Usage.RequestSizeKB),
+	}
+
+	return v
+}
+
+// Components returns the price component queries that make up the SQSQueue.
+func (v *SQSQueue) Components() []query.Component {
+	components := []query.Component{v.sqsQueueComponent()}
+	return components
+}
+
+func (v *SQSQueue) sqsQueueComponent() query.Component {
+	// Requests-RBP for us or Requests-Tier1
+	// Requests is no FIFO
+	queueType := ".*Requests-[^F].*"
+	if v.fifoQueue {
+		queueType = ".*Requests-FIFO.*"
+	}
+
+	requests := v.requestSizeKB.Div(decimal.NewFromInt(64)).Ceil().Mul(v.monthlyRequests)
+
+	return query.Component{
+		Name:            fmt.Sprintf("Requests %s", queueType),
+		MonthlyQuantity: requests,
+		Details:         []string{"SQS queue", queueType},
+		Usage:           true,
+		Unit:            "Requests",
+		ProductFilter: &product.Filter{
+			Provider: util.StringPtr(v.provider.key),
+			Service:  util.StringPtr("AWSQueueService"),
+			Family:   util.StringPtr("API Request"),
+			Location: util.StringPtr(v.region.String()),
+			AttributeFilters: []*product.AttributeFilter{
+				{Key: "UsageType", ValueRegex: util.StringPtr(queueType)},
+			},
+		},
+		PriceFilter: &price.Filter{
+			Unit: util.StringPtr("Requests"),
+			AttributeFilters: []*price.AttributeFilter{
+				{Key: "TermType", Value: util.StringPtr("OnDemand")},
+				{Key: "StartingRange", Value: util.StringPtr("0")},
+			},
+		},
+	}
+}
diff --git a/docs/aws.md b/docs/aws.md
index 3d5b8ee..97ea30c 100644
--- a/docs/aws.md
+++ b/docs/aws.md
@@ -26,6 +26,8 @@ done
 
 * [`aws_instance`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance)
 * [`aws_autoscaling_group`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/autoscaling_group)
+* [`aws_cloudwatch_log_group`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group)
+* [`aws_cloudwatch_metric_alarm`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_metric_alarm)
 * [`aws_db_instance`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_instance)
 * [`aws_ebs_volume`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ebs_volume)
 * [`aws_efs_file_system`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/efs_file_system)
@@ -39,6 +41,24 @@ done
 * [`aws_fsx_ontap_file_system`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/fsx_ontap_file_system)
 * [`aws_fsx_openzfs_file_system`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/fsx_openzfs_file_system)
 * [`aws_fsx_windows_file_system`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/fsx_windows_file_system)
+* [`aws_kms_key`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key)
 * [`aws_lb`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb)
 * [`aws_alb`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/alb)
-* [`aws_nat_gateway`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/nat_gateway)
\ No newline at end of file
+* [`aws_nat_gateway`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/nat_gateway)
+* [`aws_rds_cluster`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster)
+* [`aws_rds_cluster_instance`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster_instance)
+* [`aws_s3_bucket`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket)
+* [`aws_s3_bucket_analytics_configuration`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_analytics_configuration)
+* [`aws_s3_bucket_inventory`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_inventory)
+* [`aws_secretsmanager_secret`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret)
+* [`aws_sqs_queue`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sqs_queue)
+
+## List of identified resources with zero cost or no estimation.
+* [`aws_db_subnet_group`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_subnet_group)
+* [`aws_elasticache_subnet_group`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/elasticache_subnet_group)
+* [`aws_s3_bucket_accelerate_configuration`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_accelerate_configuration)
+* [`aws_s3_bucket_versioning`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning)
+* [`aws_s3_bucket_intelligent_tiering_configuration`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_intelligent_tiering_configuration)
+* [`aws_s3_bucket_metric`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_metric)
+* [`aws_secretsmanager_secret_version`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret_version)
+* [`aws_rds_cluster_endpoint`](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster_endpoint)
\ No newline at end of file
diff --git a/examples/README.md b/examples/README.md
index 9de77ad..1b2cd5e 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -24,8 +24,8 @@ mysql -h 127.0.0.1 -uroot -pterracost -e "CREATE DATABASE terracost_test"
 To start prices ingestion you need to first decide which cloud provider to ingest. In the example `aws` or `azurerm` are availables with `-ingest -provider`.
 
 ```
-go run terracost.go -ingest -provider aws -ingest-aws-region eu-west-1
-go run terracost.go -ingest -provider azurerm -ingest-azure-region francecentral
+go run terracost.go -ingest -provider aws -ingest-region eu-west-1
+go run terracost.go -ingest -provider azurerm -ingest-region francecentral
 ```
 
 > Note
diff --git a/usage/usage.go b/usage/usage.go
index e51d95c..ba3b883 100644
--- a/usage/usage.go
+++ b/usage/usage.go
@@ -10,6 +10,11 @@ const (
 var Default = Usage{
 	ResourceDefaultTypeUsage: map[string]interface{}{
 		// AWS
+		"aws_cloudwatch_log_group": map[string]interface{}{
+			"storage_gb":                       200,
+			"monthly_data_ingested_gb":         10,
+			"monthly_data_scanned_insights_gb": 20,
+		},
 		"aws_eks_node_group": map[string]interface{}{
 			"instances":                        15,
 			"operating_system":                 "linux",
@@ -40,6 +45,39 @@ var Default = Usage{
 		"aws_nat_gateway": map[string]interface{}{
 			"monthly_data_processed_gb": 10,
 		},
+		"aws_rds_cluster": map[string]interface{}{
+			"capacity_units_per_hr":        0.5,
+			"storage_gb":                   50,
+			"write_requests_per_sec":       4,
+			"read_requests_per_sec":        4,
+			"backup_snapshot_size_gb":      60,
+			"average_statements_per_hr":    2500,
+			"change_records_per_statement": 0.095,
+			"backtrack_window_hrs":         150,
+			"snapshot_export_size_gb":      300,
+		},
+		"aws_rds_cluster_instance": map[string]interface{}{
+			"monthly_additional_performance_insights_requests": 500000,
+			"capacity_units_per_hr":                            0.5,
+		},
+		"aws_s3_bucket": map[string]interface{}{
+			"storage_gb":               200,
+			"monthly_outbound_data_gb": 10,
+		},
+		"aws_s3_bucket_analytics_configuration": map[string]interface{}{
+			"monthly_monitored_objects": 50000000,
+		},
+
+		"aws_s3_bucket_inventory": map[string]interface{}{
+			"monthly_listed_objects": 2000000000,
+		},
+		"aws_secretsmanager_secret": map[string]interface{}{
+			"monthly_requests": 1000000,
+		},
+		"aws_sqs_queue": map[string]interface{}{
+			"monthly_requests": 15000000,
+			"request_size_kb":  16,
+		},
 
 		// Azure
 		"azurerm_bastion_host": map[string]interface{}{


Test patch:
diff --git a/aws/terraform/cloudwatch_log_group_test.go b/aws/terraform/cloudwatch_log_group_test.go
new file mode 100644
index 0000000..b96b99e
--- /dev/null
+++ b/aws/terraform/cloudwatch_log_group_test.go
@@ -0,0 +1,110 @@
+package terraform_test
+
+import (
+	"testing"
+
+	"github.com/shopspring/decimal"
+	"github.com/stretchr/testify/require"
+
+	awstf "github.com/cycloidio/terracost/aws/terraform"
+	"github.com/cycloidio/terracost/price"
+	"github.com/cycloidio/terracost/product"
+	"github.com/cycloidio/terracost/query"
+	"github.com/cycloidio/terracost/terraform"
+	"github.com/cycloidio/terracost/testutil"
+	"github.com/cycloidio/terracost/usage"
+	"github.com/cycloidio/terracost/util"
+)
+
+func TestCloudwatchLogGroup_Components(t *testing.T) {
+	p, err := awstf.NewProvider("aws", "eu-west-1")
+	require.NoError(t, err)
+
+	t.Run("LogGroup", func(t *testing.T) {
+		tfres := terraform.Resource{
+			Address:      "aws_cloudwatch_log_group.test",
+			Type:         "aws_cloudwatch_log_group",
+			Name:         "test",
+			ProviderName: "aws",
+			Values:       map[string]interface{}{},
+		}
+		rss := map[string]terraform.Resource{}
+
+		expected := []query.Component{
+			{
+				Name:            "Data ingested",
+				MonthlyQuantity: decimal.NewFromFloat(10),
+				Unit:            "GB",
+				Details:         []string{"Data ingested"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AmazonCloudWatch"),
+					Family:   util.StringPtr("Data Payload"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*-DataProcessing-Bytes")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("GB"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+			{
+				Name:            "Archival Storage",
+				MonthlyQuantity: decimal.NewFromFloat(200),
+				Unit:            "GB-Mo",
+				Details:         []string{"Archival Storage"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AmazonCloudWatch"),
+					Family:   util.StringPtr("Storage Snapshot"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*-TimedStorage-ByteHrs")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("GB-Mo"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+			{
+				Name:            "Insights queries data scanned",
+				MonthlyQuantity: decimal.NewFromFloat(20),
+				Unit:            "GB",
+				Details:         []string{"Insights queries", "data scanned", "Storage"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AmazonCloudWatch"),
+					Family:   util.StringPtr("Data Payload"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*-DataScanned-Bytes")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("GB"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+		}
+
+		us := usage.Default.GetUsage("aws_cloudwatch_log_group")
+		tfres.Values[usage.Key] = us
+		actual := p.ResourceComponents(rss, tfres)
+		testutil.EqualQueryComponents(t, expected, actual)
+	})
+}
diff --git a/aws/terraform/cloudwatch_metric_alarm_test.go b/aws/terraform/cloudwatch_metric_alarm_test.go
new file mode 100644
index 0000000..f659afe
--- /dev/null
+++ b/aws/terraform/cloudwatch_metric_alarm_test.go
@@ -0,0 +1,131 @@
+package terraform_test
+
+import (
+	"testing"
+
+	"github.com/shopspring/decimal"
+	"github.com/stretchr/testify/require"
+
+	awstf "github.com/cycloidio/terracost/aws/terraform"
+	"github.com/cycloidio/terracost/price"
+	"github.com/cycloidio/terracost/product"
+	"github.com/cycloidio/terracost/query"
+	"github.com/cycloidio/terracost/terraform"
+	"github.com/cycloidio/terracost/testutil"
+	"github.com/cycloidio/terracost/usage"
+	"github.com/cycloidio/terracost/util"
+)
+
+func TestCloudwatchMetricAlarm_Components(t *testing.T) {
+	p, err := awstf.NewProvider("aws", "eu-west-1")
+	require.NoError(t, err)
+
+	t.Run("AlarmStandard", func(t *testing.T) {
+		tfres := terraform.Resource{
+			Address:      "aws_cloudwatch_metric_alarm.test",
+			Type:         "aws_cloudwatch_metric_alarm",
+			Name:         "test",
+			ProviderName: "aws",
+			Values: map[string]interface{}{
+				"comparison_operator": "GreaterThanOrEqualToThreshold",
+				"period":              60,
+				"metric_query": []interface{}{
+					map[string]interface{}{
+						"metric": map[string]interface{}{
+							"period": 180,
+						},
+					},
+					map[string]interface{}{
+						"metric": map[string]interface{}{
+							"period": 60,
+						},
+					},
+				},
+			},
+		}
+		rss := map[string]terraform.Resource{}
+
+		expected := []query.Component{
+			{
+				Name:            "Standard resolution",
+				MonthlyQuantity: decimal.NewFromFloat(2),
+				Unit:            "alarm metrics",
+				Details:         []string{"Standard resolution", "Standard"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AmazonCloudWatch"),
+					Family:   util.StringPtr("Alarm"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*AlarmMonitorUsage")},
+						{Key: "AlarmType", Value: util.StringPtr("Standard")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("Alarms"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+		}
+
+		us := usage.Default.GetUsage("aws_cloudwatch_metric_alarm")
+		tfres.Values[usage.Key] = us
+		actual := p.ResourceComponents(rss, tfres)
+		testutil.EqualQueryComponents(t, expected, actual)
+	})
+
+	t.Run("AlarmHigh", func(t *testing.T) {
+		tfres := terraform.Resource{
+			Address:      "aws_cloudwatch_metric_alarm.test",
+			Type:         "aws_cloudwatch_metric_alarm",
+			Name:         "test",
+			ProviderName: "aws",
+			Values: map[string]interface{}{
+				"comparison_operator": "LessThanLowerOrGreaterThanUpperThreshold",
+				"period":              30,
+				"metric_query": []interface{}{
+					map[string]interface{}{
+						"metric": map[string]interface{}{},
+					},
+				},
+			},
+		}
+		rss := map[string]terraform.Resource{}
+
+		expected := []query.Component{
+			{
+				Name:            "High resolution anomaly detection",
+				MonthlyQuantity: decimal.NewFromFloat(3),
+				Unit:            "Alarms",
+				Details:         []string{"High resolution anomaly detection", "High Resolution"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AmazonCloudWatch"),
+					Family:   util.StringPtr("Alarm"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*AlarmMonitorUsage")},
+						{Key: "AlarmType", Value: util.StringPtr("High Resolution")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("Alarms"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+		}
+
+		us := usage.Default.GetUsage("aws_cloudwatch_metric_alarm")
+		tfres.Values[usage.Key] = us
+		actual := p.ResourceComponents(rss, tfres)
+		testutil.EqualQueryComponents(t, expected, actual)
+	})
+}
diff --git a/aws/terraform/elasticache_replication_group_test.go b/aws/terraform/elasticache_replication_group_test.go
index ecb8b93..6d282af 100644
--- a/aws/terraform/elasticache_replication_group_test.go
+++ b/aws/terraform/elasticache_replication_group_test.go
@@ -193,7 +193,7 @@ func TestElastiCacheReplication_Components(t *testing.T) {
 				"node_type": "cache.m4.large",
 				"engine":    "redis",
 				"cluster_mode": []map[string]int{
-					map[string]int{
+					{
 						"replicas_per_node_group": 3,
 						"num_node_groups":         2,
 					},
diff --git a/aws/terraform/kms_key_test.go b/aws/terraform/kms_key_test.go
new file mode 100644
index 0000000..05f9d12
--- /dev/null
+++ b/aws/terraform/kms_key_test.go
@@ -0,0 +1,203 @@
+package terraform_test
+
+import (
+	"testing"
+
+	"github.com/shopspring/decimal"
+	"github.com/stretchr/testify/require"
+
+	awstf "github.com/cycloidio/terracost/aws/terraform"
+	"github.com/cycloidio/terracost/price"
+	"github.com/cycloidio/terracost/product"
+	"github.com/cycloidio/terracost/query"
+	"github.com/cycloidio/terracost/terraform"
+	"github.com/cycloidio/terracost/testutil"
+	"github.com/cycloidio/terracost/usage"
+	"github.com/cycloidio/terracost/util"
+)
+
+func TestKMSKey_Components(t *testing.T) {
+	p, err := awstf.NewProvider("aws", "eu-west-1")
+	require.NoError(t, err)
+
+	t.Run("SYMMETRIC_DEFAULT", func(t *testing.T) {
+		tfres := terraform.Resource{
+			Address:      "aws_kms_key.test",
+			Type:         "aws_kms_key",
+			Name:         "test",
+			ProviderName: "aws",
+			Values: map[string]interface{}{
+				"customer_master_key_spec": "SYMMETRIC_DEFAULT",
+			},
+		}
+		rss := map[string]terraform.Resource{}
+
+		expected := []query.Component{
+			{
+				Name:            "Customer master key",
+				MonthlyQuantity: decimal.NewFromFloat(1),
+				Unit:            "Keys",
+				Details:         []string{"master key"},
+				Usage:           false,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("awskms"),
+					Family:   util.StringPtr("Encryption Key"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*KMS-Keys")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("Keys"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+			{
+				Name:            "Requests",
+				MonthlyQuantity: decimal.NewFromFloat(1),
+				Unit:            "Requests",
+				Details:         []string{"Request"},
+				Usage:           false,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("awskms"),
+					Family:   util.StringPtr("API Request"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*KMS-Requests$")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("Requests"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+			{
+				Name:            "ECC GenerateDataKeyPair requests",
+				MonthlyQuantity: decimal.NewFromFloat(1),
+				Unit:            "Requests",
+				Details:         []string{"Request"},
+				Usage:           false,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("awskms"),
+					Family:   util.StringPtr(""),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*KMS-Requests-GenerateDatakeyPair-ECC$")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("Requests"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+			{
+				Name:            "RSA GenerateDataKeyPair requests",
+				MonthlyQuantity: decimal.NewFromFloat(1),
+				Unit:            "Requests",
+				Details:         []string{"Request"},
+				Usage:           false,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("awskms"),
+					Family:   util.StringPtr(""),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*KMS-Requests-GenerateDatakeyPair-RSA$")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("Requests"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+		}
+
+		us := usage.Default.GetUsage("aws_cloudwatch_metric_alarm")
+		tfres.Values[usage.Key] = us
+		actual := p.ResourceComponents(rss, tfres)
+		testutil.EqualQueryComponents(t, expected, actual)
+	})
+
+	t.Run("RSA_4096", func(t *testing.T) {
+		tfres := terraform.Resource{
+			Address:      "aws_kms_key.test",
+			Type:         "aws_kms_key",
+			Name:         "test",
+			ProviderName: "aws",
+			Values: map[string]interface{}{
+				"customer_master_key_spec": "RSA_4096",
+			},
+		}
+		rss := map[string]terraform.Resource{}
+
+		expected := []query.Component{
+			{
+				Name:            "Customer master key",
+				MonthlyQuantity: decimal.NewFromFloat(1),
+				Unit:            "Keys",
+				Details:         []string{"master key"},
+				Usage:           false,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("awskms"),
+					Family:   util.StringPtr("Encryption Key"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*KMS-Keys")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("Keys"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+			{
+				Name:            "Requests (asymmetric)",
+				MonthlyQuantity: decimal.NewFromFloat(1),
+				Unit:            "Requests",
+				Details:         []string{"Request"},
+				Usage:           false,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("awskms"),
+					Family:   util.StringPtr(""),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*KMS-Requests-Asymmetric$")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("Requests"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+		}
+
+		us := usage.Default.GetUsage("aws_cloudwatch_metric_alarm")
+		tfres.Values[usage.Key] = us
+		actual := p.ResourceComponents(rss, tfres)
+		testutil.EqualQueryComponents(t, expected, actual)
+	})
+
+}
diff --git a/aws/terraform/rds_cluster_instance_test.go b/aws/terraform/rds_cluster_instance_test.go
new file mode 100644
index 0000000..7ec8f45
--- /dev/null
+++ b/aws/terraform/rds_cluster_instance_test.go
@@ -0,0 +1,118 @@
+package terraform_test
+
+import (
+	"testing"
+
+	"github.com/shopspring/decimal"
+	"github.com/stretchr/testify/require"
+
+	awstf "github.com/cycloidio/terracost/aws/terraform"
+	"github.com/cycloidio/terracost/price"
+	"github.com/cycloidio/terracost/product"
+	"github.com/cycloidio/terracost/query"
+	"github.com/cycloidio/terracost/terraform"
+	"github.com/cycloidio/terracost/testutil"
+	"github.com/cycloidio/terracost/usage"
+	"github.com/cycloidio/terracost/util"
+)
+
+func TestRDSClusterInstance_Components(t *testing.T) {
+	p, err := awstf.NewProvider("aws", "eu-west-1")
+	require.NoError(t, err)
+
+	t.Run("RDSClusterInstanceMysql", func(t *testing.T) {
+		tfres := terraform.Resource{
+			Address:      "aws_rds_cluster_instance.test",
+			Type:         "aws_rds_cluster_instance",
+			Name:         "test",
+			ProviderName: "aws",
+			Values: map[string]interface{}{
+				"engine":                                "aurora-mysql",
+				"instance_class":                        "db.r4.large",
+				"performance_insights_retention_period": 31,
+				"performance_insights_enabled":          true,
+			},
+		}
+		rss := map[string]terraform.Resource{}
+
+		expected := []query.Component{
+			{
+				Name:           "Database instance",
+				HourlyQuantity: decimal.NewFromFloat(1),
+				Unit:           "Hrs",
+				Details:        []string{"instance"},
+				Usage:          false,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AmazonRDS"),
+					Family:   util.StringPtr("Database Instance"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "InstanceType", Value: util.StringPtr("db.r4.large")},
+						{Key: "DatabaseEngine", Value: util.StringPtr("Aurora MySQL")},
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*InstanceUsage:.*")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("Hrs"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+			{
+				Name:            "Performance Insights Long Term Retention (serverless)",
+				MonthlyQuantity: decimal.NewFromFloat(0.5),
+				Unit:            "ACU-Months",
+				Details:         []string{"Insights"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AmazonRDS"),
+					Family:   util.StringPtr("Performance Insights"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "DatabaseEngine", Value: util.StringPtr("Aurora MySQL")},
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*PI_LTR_FMR:Serverless$")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("ACU-Months"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+			{
+				Name:            "Performance Insights API",
+				MonthlyQuantity: decimal.NewFromFloat(500000),
+				Unit:            "API Calls",
+				Details:         []string{"Requests"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AmazonRDS"),
+					Family:   util.StringPtr("Performance Insights"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*PI_API$")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("API Calls"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+		}
+
+		us := usage.Default.GetUsage("aws_rds_cluster_instance")
+		tfres.Values[usage.Key] = us
+		actual := p.ResourceComponents(rss, tfres)
+		testutil.EqualQueryComponents(t, expected, actual)
+	})
+}
diff --git a/aws/terraform/rds_cluster_test.go b/aws/terraform/rds_cluster_test.go
new file mode 100644
index 0000000..e59b0dc
--- /dev/null
+++ b/aws/terraform/rds_cluster_test.go
@@ -0,0 +1,312 @@
+package terraform_test
+
+import (
+	"testing"
+
+	"github.com/shopspring/decimal"
+	"github.com/stretchr/testify/require"
+
+	awstf "github.com/cycloidio/terracost/aws/terraform"
+	"github.com/cycloidio/terracost/price"
+	"github.com/cycloidio/terracost/product"
+	"github.com/cycloidio/terracost/query"
+	"github.com/cycloidio/terracost/terraform"
+	"github.com/cycloidio/terracost/testutil"
+	"github.com/cycloidio/terracost/usage"
+	"github.com/cycloidio/terracost/util"
+)
+
+func TestRDSCluster_Components(t *testing.T) {
+	p, err := awstf.NewProvider("aws", "eu-west-1")
+	require.NoError(t, err)
+
+	t.Run("RDSClusterMysql", func(t *testing.T) {
+		tfres := terraform.Resource{
+			Address:      "aws_rds_cluster.test",
+			Type:         "aws_rds_cluster",
+			Name:         "test",
+			ProviderName: "aws",
+			Values: map[string]interface{}{
+				"engine":                  "aurora-mysql",
+				"backup_retention_period": 15,
+			},
+		}
+		rss := map[string]terraform.Resource{}
+
+		expected := []query.Component{
+			{
+				Name:            "Storage",
+				MonthlyQuantity: decimal.NewFromFloat(50),
+				Unit:            "GB-Mo",
+				Details:         []string{"Storage"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AmazonRDS"),
+					Family:   util.StringPtr("Database Storage"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "DatabaseEngine", ValueRegex: util.StringPtr("Any")},
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*Aurora:StorageUsage$")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("GB-Mo"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+			{
+				Name:            "I/O requests",
+				MonthlyQuantity: decimal.NewFromFloat(21024000),
+				Unit:            "IOs",
+				Details:         []string{"I/O requests"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AmazonRDS"),
+					Family:   util.StringPtr("System Operation"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "DatabaseEngine", ValueRegex: util.StringPtr("Any")},
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*Aurora:StorageIOUsage$")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("IOs"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+			{
+				Name:            "Backup storage",
+				MonthlyQuantity: decimal.NewFromFloat(840),
+				Unit:            "GB-Mo",
+				Details:         []string{"Aurora MySQL"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AmazonRDS"),
+					Family:   util.StringPtr("Storage Snapshot"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "DatabaseEngine", Value: util.StringPtr("Aurora MySQL")},
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*Aurora:BackupUsage$")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("GB-Mo"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+			{
+				Name:            "Backtrack",
+				MonthlyQuantity: decimal.NewFromFloat(26006250),
+				Unit:            "CR-Hr",
+				Details:         []string{"Backtrack"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AmazonRDS"),
+					Family:   util.StringPtr("System Operation"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*Aurora:BacktrackUsage$")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("CR-Hr"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+			{
+				Name:            "Snapshot export",
+				MonthlyQuantity: decimal.NewFromFloat(300),
+				Unit:            "GB",
+				Details:         []string{"Snapshot"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AmazonRDS"),
+					Family:   util.StringPtr("System Operation"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "DatabaseEngine", Value: util.StringPtr("Aurora MySQL")},
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*Aurora:SnapshotExportToS3$")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("GB"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+		}
+
+		us := usage.Default.GetUsage("aws_rds_cluster")
+		tfres.Values[usage.Key] = us
+		actual := p.ResourceComponents(rss, tfres)
+		testutil.EqualQueryComponents(t, expected, actual)
+	})
+
+	t.Run("RDSClusterServerlessPostgres", func(t *testing.T) {
+		tfres := terraform.Resource{
+			Address:      "aws_rds_cluster.test",
+			Type:         "aws_rds_cluster",
+			Name:         "test",
+			ProviderName: "aws",
+			Values: map[string]interface{}{
+				"engine":                  "aurora-postgresql",
+				"backup_retention_period": 15,
+				"storage_type":            "aurora-iopt1",
+				"serverlessv2_scaling_configuration": []interface{}{
+					map[string]interface{}{
+						"min_capacity": 1,
+					},
+				},
+			},
+		}
+		rss := map[string]terraform.Resource{}
+
+		expected := []query.Component{
+			{
+				Name:            "Storage (I/O-optimized)",
+				MonthlyQuantity: decimal.NewFromFloat(50),
+				Unit:            "GB-Mo",
+				Details:         []string{"Storage (I/O-optimized)"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AmazonRDS"),
+					Family:   util.StringPtr("Database Storage"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "DatabaseEngine", ValueRegex: util.StringPtr("Aurora PostgreSQL")},
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*Aurora:IO-OptimizedStorageUsage$")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("GB-Mo"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+			{
+				Name:            "I/O requests",
+				MonthlyQuantity: decimal.NewFromFloat(21024000),
+				Unit:            "IOs",
+				Details:         []string{"I/O requests"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AmazonRDS"),
+					Family:   util.StringPtr("System Operation"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "DatabaseEngine", ValueRegex: util.StringPtr("Aurora PostgreSQL")},
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*Aurora:StorageIOUsage$")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("IOs"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+			{
+				Name:            "Aurora ServerlessV2",
+				MonthlyQuantity: decimal.NewFromFloat(0.5),
+				Unit:            "ACU-Hr",
+				Details:         []string{"Aurora PostgreSQL"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AmazonRDS"),
+					Family:   util.StringPtr("ServerlessV2"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "DatabaseEngine", Value: util.StringPtr("Aurora PostgreSQL")},
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*Aurora:ServerlessV2IOOptimizedUsage$")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("ACU-Hr"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+			{
+				Name:            "Backup storage",
+				MonthlyQuantity: decimal.NewFromFloat(840),
+				Unit:            "GB-Mo",
+				Details:         []string{"Aurora PostgreSQL"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AmazonRDS"),
+					Family:   util.StringPtr("Storage Snapshot"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "DatabaseEngine", Value: util.StringPtr("Aurora PostgreSQL")},
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*Aurora:BackupUsage$")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("GB-Mo"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+
+			{
+				Name:            "Snapshot export",
+				MonthlyQuantity: decimal.NewFromFloat(300),
+				Unit:            "GB",
+				Details:         []string{"Snapshot"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AmazonRDS"),
+					Family:   util.StringPtr("System Operation"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "DatabaseEngine", Value: util.StringPtr("Aurora PostgreSQL")},
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*Aurora:SnapshotExportToS3$")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("GB"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+		}
+
+		us := usage.Default.GetUsage("aws_rds_cluster")
+		tfres.Values[usage.Key] = us
+		actual := p.ResourceComponents(rss, tfres)
+		testutil.EqualQueryComponents(t, expected, actual)
+	})
+}
diff --git a/aws/terraform/s3_bucket_analytics_configuration_test.go b/aws/terraform/s3_bucket_analytics_configuration_test.go
new file mode 100644
index 0000000..af45174
--- /dev/null
+++ b/aws/terraform/s3_bucket_analytics_configuration_test.go
@@ -0,0 +1,64 @@
+package terraform_test
+
+import (
+	"testing"
+
+	"github.com/shopspring/decimal"
+	"github.com/stretchr/testify/require"
+
+	awstf "github.com/cycloidio/terracost/aws/terraform"
+	"github.com/cycloidio/terracost/price"
+	"github.com/cycloidio/terracost/product"
+	"github.com/cycloidio/terracost/query"
+	"github.com/cycloidio/terracost/terraform"
+	"github.com/cycloidio/terracost/testutil"
+	"github.com/cycloidio/terracost/usage"
+	"github.com/cycloidio/terracost/util"
+)
+
+func TestS3BucketAnalyticsConfiguration_Components(t *testing.T) {
+	p, err := awstf.NewProvider("aws", "eu-west-1")
+	require.NoError(t, err)
+
+	t.Run("ObjectsMonitored", func(t *testing.T) {
+		tfres := terraform.Resource{
+			Address:      "aws_s3_bucket_analytics_configuration.test",
+			Type:         "aws_s3_bucket_analytics_configuration",
+			Name:         "test",
+			ProviderName: "aws",
+			Values:       map[string]interface{}{},
+		}
+		rss := map[string]terraform.Resource{}
+
+		expected := []query.Component{
+			{
+				Name:            "Objects monitored",
+				MonthlyQuantity: decimal.NewFromFloat(0),
+				Unit:            "Objects",
+				Details:         []string{"Monitored"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AmazonS3"),
+					Family:   util.StringPtr("Fee"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*StorageAnalytics-ObjCount$")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("Objects"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+		}
+
+		us := usage.Default.GetUsage("aws_cloudwatch_metric_alarm")
+		tfres.Values[usage.Key] = us
+		actual := p.ResourceComponents(rss, tfres)
+		testutil.EqualQueryComponents(t, expected, actual)
+	})
+}
diff --git a/aws/terraform/s3_bucket_inventory_test.go b/aws/terraform/s3_bucket_inventory_test.go
new file mode 100644
index 0000000..afa1f0e
--- /dev/null
+++ b/aws/terraform/s3_bucket_inventory_test.go
@@ -0,0 +1,64 @@
+package terraform_test
+
+import (
+	"testing"
+
+	"github.com/shopspring/decimal"
+	"github.com/stretchr/testify/require"
+
+	awstf "github.com/cycloidio/terracost/aws/terraform"
+	"github.com/cycloidio/terracost/price"
+	"github.com/cycloidio/terracost/product"
+	"github.com/cycloidio/terracost/query"
+	"github.com/cycloidio/terracost/terraform"
+	"github.com/cycloidio/terracost/testutil"
+	"github.com/cycloidio/terracost/usage"
+	"github.com/cycloidio/terracost/util"
+)
+
+func TestS3BucketInventory_Components(t *testing.T) {
+	p, err := awstf.NewProvider("aws", "eu-west-1")
+	require.NoError(t, err)
+
+	t.Run("ObjectsMonitored", func(t *testing.T) {
+		tfres := terraform.Resource{
+			Address:      "aws_s3_bucket_inventory.test",
+			Type:         "aws_s3_bucket_inventory",
+			Name:         "test",
+			ProviderName: "aws",
+			Values:       map[string]interface{}{},
+		}
+		rss := map[string]terraform.Resource{}
+
+		expected := []query.Component{
+			{
+				Name:            "Objects listed",
+				MonthlyQuantity: decimal.NewFromFloat(0),
+				Unit:            "Objects",
+				Details:         []string{"Listed"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AmazonS3"),
+					Family:   util.StringPtr("Fee"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*Inventory-ObjectsListed$")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("Objects"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+		}
+
+		us := usage.Default.GetUsage("aws_cloudwatch_metric_alarm")
+		tfres.Values[usage.Key] = us
+		actual := p.ResourceComponents(rss, tfres)
+		testutil.EqualQueryComponents(t, expected, actual)
+	})
+}
diff --git a/aws/terraform/s3_bucket_test.go b/aws/terraform/s3_bucket_test.go
new file mode 100644
index 0000000..c2ea240
--- /dev/null
+++ b/aws/terraform/s3_bucket_test.go
@@ -0,0 +1,88 @@
+package terraform_test
+
+import (
+	"testing"
+
+	"github.com/shopspring/decimal"
+	"github.com/stretchr/testify/require"
+
+	awstf "github.com/cycloidio/terracost/aws/terraform"
+	"github.com/cycloidio/terracost/price"
+	"github.com/cycloidio/terracost/product"
+	"github.com/cycloidio/terracost/query"
+	"github.com/cycloidio/terracost/terraform"
+	"github.com/cycloidio/terracost/testutil"
+	"github.com/cycloidio/terracost/usage"
+	"github.com/cycloidio/terracost/util"
+)
+
+func TestS3Bucket_Components(t *testing.T) {
+	p, err := awstf.NewProvider("aws", "eu-west-1")
+	require.NoError(t, err)
+
+	t.Run("S3Bucket", func(t *testing.T) {
+		tfres := terraform.Resource{
+			Address:      "aws_s3_bucket.test",
+			Type:         "aws_s3_bucket",
+			Name:         "test",
+			ProviderName: "aws",
+			Values:       map[string]interface{}{},
+		}
+		rss := map[string]terraform.Resource{}
+
+		expected := []query.Component{
+			{
+				Name:            "Storage 0",
+				MonthlyQuantity: decimal.NewFromFloat(200),
+				Unit:            "GB-Mo",
+				Details:         []string{"Standard"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AmazonS3"),
+					Family:   util.StringPtr("Storage"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*TimedStorage-ByteHrs$")},
+						{Key: "VolumeType", Value: util.StringPtr("Standard")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("GB-Mo"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+			{
+				Name:            "Outbound Data Transfer 0",
+				MonthlyQuantity: decimal.NewFromFloat(10),
+				Unit:            "GB",
+				Details:         []string{"Outbound"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AWSDataTransfer"),
+					Family:   util.StringPtr("Data Transfer"),
+					Location: util.StringPtr(""),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "UsageType", Value: util.StringPtr("EU-DataTransfer-Out-Bytes")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("GB"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+		}
+
+		us := usage.Default.GetUsage("aws_s3_bucket")
+		tfres.Values[usage.Key] = us
+		actual := p.ResourceComponents(rss, tfres)
+		testutil.EqualQueryComponents(t, expected, actual)
+	})
+}
diff --git a/aws/terraform/secretsmanager_secret_test.go b/aws/terraform/secretsmanager_secret_test.go
new file mode 100644
index 0000000..e327855
--- /dev/null
+++ b/aws/terraform/secretsmanager_secret_test.go
@@ -0,0 +1,88 @@
+package terraform_test
+
+import (
+	"testing"
+
+	"github.com/shopspring/decimal"
+	"github.com/stretchr/testify/require"
+
+	awstf "github.com/cycloidio/terracost/aws/terraform"
+	"github.com/cycloidio/terracost/price"
+	"github.com/cycloidio/terracost/product"
+	"github.com/cycloidio/terracost/query"
+	"github.com/cycloidio/terracost/terraform"
+	"github.com/cycloidio/terracost/testutil"
+	"github.com/cycloidio/terracost/usage"
+	"github.com/cycloidio/terracost/util"
+)
+
+func TestSecretsmanagerSecret_Components(t *testing.T) {
+	p, err := awstf.NewProvider("aws", "eu-west-1")
+	require.NoError(t, err)
+
+	t.Run("Secret", func(t *testing.T) {
+		tfres := terraform.Resource{
+			Address:      "aws_secretsmanager_secret.test",
+			Type:         "aws_secretsmanager_secret",
+			Name:         "test",
+			ProviderName: "aws",
+			Values:       map[string]interface{}{},
+		}
+		rss := map[string]terraform.Resource{}
+
+		expected := []query.Component{
+			{
+				Name:            "Secret",
+				MonthlyQuantity: decimal.NewFromFloat(1),
+				Unit:            "Secrets",
+				Details:         []string{"Secret"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AWSSecretsManager"),
+					Family:   util.StringPtr("Secret"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*-AWSSecretsManager-Secrets")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("Secrets"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+
+			{
+				Name:            "API Request",
+				MonthlyQuantity: decimal.NewFromFloat(1000000),
+				Unit:            "API Requests",
+				Details:         []string{"API Request"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AWSSecretsManager"),
+					Family:   util.StringPtr("API Request"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*-AWSSecretsManager[-]?APIRequest[s]?")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("API Requests"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+		}
+
+		us := usage.Default.GetUsage("aws_secretsmanager_secret")
+		tfres.Values[usage.Key] = us
+		actual := p.ResourceComponents(rss, tfres)
+		testutil.EqualQueryComponents(t, expected, actual)
+	})
+}
diff --git a/aws/terraform/sqs_queue_test.go b/aws/terraform/sqs_queue_test.go
new file mode 100644
index 0000000..5b12912
--- /dev/null
+++ b/aws/terraform/sqs_queue_test.go
@@ -0,0 +1,108 @@
+package terraform_test
+
+import (
+	"testing"
+
+	"github.com/shopspring/decimal"
+	"github.com/stretchr/testify/require"
+
+	awstf "github.com/cycloidio/terracost/aws/terraform"
+	"github.com/cycloidio/terracost/price"
+	"github.com/cycloidio/terracost/product"
+	"github.com/cycloidio/terracost/query"
+	"github.com/cycloidio/terracost/terraform"
+	"github.com/cycloidio/terracost/testutil"
+	"github.com/cycloidio/terracost/usage"
+	"github.com/cycloidio/terracost/util"
+)
+
+func TestSQSQueue_Components(t *testing.T) {
+	p, err := awstf.NewProvider("aws", "eu-west-1")
+	require.NoError(t, err)
+
+	t.Run("FIFO", func(t *testing.T) {
+		tfres := terraform.Resource{
+			Address:      "aws_sqs_queue.test",
+			Type:         "aws_sqs_queue",
+			Name:         "test",
+			ProviderName: "aws",
+			Values: map[string]interface{}{
+				"fifo_queue": true,
+			},
+		}
+		rss := map[string]terraform.Resource{}
+
+		expected := []query.Component{
+			{
+				Name:            "Requests .*Requests-FIFO.*",
+				MonthlyQuantity: decimal.NewFromFloat(15000000),
+				Unit:            "Requests",
+				Details:         []string{"SQS queue", ".*Requests-FIFO.*"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AWSQueueService"),
+					Family:   util.StringPtr("API Request"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*Requests-FIFO.*")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("Requests"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+		}
+
+		us := usage.Default.GetUsage("aws_sqs_queue")
+		tfres.Values[usage.Key] = us
+		actual := p.ResourceComponents(rss, tfres)
+		testutil.EqualQueryComponents(t, expected, actual)
+	})
+
+	t.Run("NOFIFO", func(t *testing.T) {
+		tfres := terraform.Resource{
+			Address:      "aws_sqs_queue.test",
+			Type:         "aws_sqs_queue",
+			Name:         "test",
+			ProviderName: "aws",
+			Values:       map[string]interface{}{},
+		}
+		rss := map[string]terraform.Resource{}
+
+		expected := []query.Component{
+			{
+				Name:            "Requests .*Requests-[^F].*",
+				MonthlyQuantity: decimal.NewFromFloat(15000000),
+				Unit:            "Requests",
+				Details:         []string{"SQS queue", ".*Requests-[^F].*"},
+				Usage:           true,
+				ProductFilter: &product.Filter{
+					Provider: util.StringPtr("aws"),
+					Service:  util.StringPtr("AWSQueueService"),
+					Family:   util.StringPtr("API Request"),
+					Location: util.StringPtr("eu-west-1"),
+					AttributeFilters: []*product.AttributeFilter{
+						{Key: "UsageType", ValueRegex: util.StringPtr(".*Requests-[^F].*")},
+					},
+				},
+				PriceFilter: &price.Filter{
+					Unit: util.StringPtr("Requests"),
+					AttributeFilters: []*price.AttributeFilter{
+						{Key: "TermType", Value: util.StringPtr("OnDemand")},
+						{Key: "StartingRange", Value: util.StringPtr("0")},
+					},
+				},
+			},
+		}
+
+		us := usage.Default.GetUsage("aws_sqs_queue")
+		tfres.Values[usage.Key] = us
+		actual := p.ResourceComponents(rss, tfres)
+		testutil.EqualQueryComponents(t, expected, actual)
+	})
+}