Implement central logging with terraform

Hi all. Terraform newbie here. I have a use-case where i want to create a module to implement central logging using AWS’s cloudwatch Observability Access Manager feature. I have the module’s main.tf config code as seen here below:

resource “aws_oam_sink” “central_logging_sink” {
name = var.sink_name
}

resource “aws_oam_sink_policy” “central_logging_sink_policy” {
provider = aws.central
sink_identifier = aws_oam_sink.central_logging_sink.id

policy = jsonencode({
“Version”: “2012-10-17”,
“Statement”: [
{
“Effect”: “Allow”,
“Principal”: { “AWS”: var.allowed_source_accounts },
“Action”: [“oam:CreateLink”, “oam:UpdateLink”],
“Resource”: “*”,
“Condition”: {
“ForAllValues:StringEquals”: {
“oam:ResourceTypes”: var.allowed_resource_types
}
}
}
]
})
}

resource “aws_oam_link” “source_link” {
provider = aws.source
sink_identifier = aws_oam_sink.central_logging_sink.id
label_template = var.account_label
resource_types = var.allowed_resource_types
}

this is what a sample module call could look like:

module “central-logging” {
providers = {
aws.central = aws
aws.source = aws.link1
}
source = “./modules”
sink_name = “CentralLoggingSink”
account_label = “$AccountName”
allowed_resource_types = [“AWS::Logs::LogGroup”, “AWS::CloudWatch::Metric”]
allowed_source_accounts = [“111111111111”]
}

The idea is the sink resource is to be only created in a central account, and the link resource is to be created in other accounts. How can this module be successfully called to create the sink in the central account, and links in multiple other accounts, since it seems terraform doesn’t permit dynamic providers? What other way could this solution be implemented better? Thank you

@nc237 The documentation explains how you can define configuration aliases in the module and pass in different providers in the caller/root module with the providers meta-argument in the module instance.

For reference, here is the configuration that you provided with the updates/fixes. You need to update the provider blocks with appropriate login and region details, and the allowed_source_accounts input variable accordingly.

./modules/central-logging/main.tf:

terraform {
  required_providers {
    aws = {
      source                = "hashicorp/aws"
      configuration_aliases = [aws.central, aws.source]
    }
  }
}

variable "sink_name" {
  type = string
}

variable "account_label" {
  type = string
}

variable "allowed_resource_types" {
  type = list(string)
}

variable "allowed_source_accounts" {
  type = list(string)
}

resource "aws_oam_sink" "central_logging_sink" {
  provider = aws.central
  name     = var.sink_name
}

resource "aws_oam_sink_policy" "central_logging_sink_policy" {
  provider        = aws.central
  sink_identifier = aws_oam_sink.central_logging_sink.id

  policy = jsonencode({
    "Version" : "2012-10-17",
    "Statement" : [
      {
        "Effect" : "Allow",
        "Principal" : { "AWS" : var.allowed_source_accounts },
        "Action" : ["oam:CreateLink", "oam:UpdateLink"],
        "Resource" : "*",
        "Condition" : {
          "ForAllValues:StringEquals" : {
            "oam:ResourceTypes" : var.allowed_resource_types
          }
        }
      }
    ]
  })
}

data "aws_caller_identity" "source" {
  provider = aws.source
}

resource "aws_oam_link" "source_link" {
  provider        = aws.source
  sink_identifier = aws_oam_sink.central_logging_sink.arn
  label_template  = var.account_label
  resource_types  = var.allowed_resource_types
  depends_on      = [aws_oam_sink_policy.central_logging_sink_policy]
}

./main.tf:

provider "aws" {
  profile = "my-central-account"
  region  = "us-east-1"
}

provider "aws" {
  alias   = "member1"
  profile = "my-member-account"
  region  = "us-east-1"
}

module "central-logging" {
  providers = {
    aws.central = aws
    aws.source  = aws.member1
  }
  source                  = "./modules/central-logging"
  sink_name               = "CentralLoggingSink"
  account_label           = "$AccountName"
  allowed_resource_types  = ["AWS::Logs::LogGroup", "AWS::CloudWatch::Metric"]
  allowed_source_accounts = ["111111111111"]
}