Brett
Brett

Reputation: 6020

terraform aws_s3_bucket region that is different to the aws provider region gets created in the same provider region

I would like to manage AWS S3 buckets with terraform and noticed that there's a region parameter for the resource.

I have an AWS provider that is configured for 1 region, and would like to use that provider to create S3 buckets in multiple regions if possible. My S3 buckets have a lot of common configuration that I don't want to repeat, so i have a local module to do all the repetitive stuff....

In mod-s3-bucket/main.tf, I have something like:

variable bucket_region {}
variable bucket_name {}

resource "aws_s3_bucket" "s3_bucket" {
   region = var.bucket_region
   bucket = var.bucket_name
}

And then in main.tf in the parent directory (tf root):

provider "aws" {
  region = "us-east-1"
}

module "somebucket" {
  source = "mod-s3-bucket"
  bucket_region = "us-east-1"
  bucket_name = "useast1-bucket"
}

module "anotherbucket" {
  source = "mod-s3-bucket"
  bucket_region = "us-east-2"
  bucket_name = "useast2-bucket"
}

When I run a terraform apply with that, both buckets get created in us-east-1 - is this expected behaviour? My understanding is that region should make the buckets get created in different regions.

Further to that, if I run a terraform plan after bucket creation, I see the following:

       ~ region                      = "us-east-1" -> "us-east-2"

on the 1 bucket, but after an apply, the region has not changed.

I know I can easily solve this by using a 2nd, aliased AWS provider, but am asking specifically about how the region parameter is meant to work for an aws_s3_bucket resource (https://www.terraform.io/docs/providers/aws/r/s3_bucket.html#region)

Upvotes: 5

Views: 14339

Answers (3)

hector
hector

Reputation: 967

Terraform informs you if you try to set the region directly in the resource:

╷
│ Error: Value for unconfigurable attribute
│ 
│   with aws_s3_bucket.my_bucket,
│   on s3.tf line 10, in resource "aws_s3_bucket" "my_bucket":
│   28:   region                      = "us-east-1"
│ 
│ Can't configure a value for "region": its value will be decided automatically based on the result of applying this configuration.

Terraform uses the configuration of the provider, where the region is set, for managing resources. Alternatively, as already mentioned, you can use multiple configurations for the same provider by making use of the alias meta-argument.

You can optionally define multiple configurations for the same provider, and select which one to use on a per-resource or per-module basis. The primary reason for this is to support multiple regions for a cloud platform; other examples include targeting multiple Docker hosts, multiple Consul hosts, etc.

...

A provider block without an alias argument is the default configuration for that provider. Resources that don't set the provider meta-argument will use the default provider configuration that matches the first word of the resource type name. link

Upvotes: 1

Brett
Brett

Reputation: 6020

The region attribute in s3 bucket resource isn't parsed as expected, there is a bug for this:

https://github.com/terraform-providers/terraform-provider-aws/issues/592

The multiple provider approach is needed.

Upvotes: 1

theonlyrao
theonlyrao

Reputation: 422

I think you'll need to do something like the docs show in this example for Replication Configuration: https://www.terraform.io/docs/providers/aws/r/s3_bucket.html#using-replication-configuration

# /root/main.tf

provider "aws" {
  region = "us-east-1"
}

provider "aws" {
  alias  = "us-east-2"
  region = "us-east-2"
}

module "somebucket" {
  source = "mod-s3-bucket"
  bucket_region = "us-east-1"
  bucket_name = "useast1-bucket"
}

module "anotherbucket" {
  source = "mod-s3-bucket"
  provider = "aws.us-east-2"
  bucket_region = "us-east-2"
  bucket_name = "useast2-bucket"
}
# /mod-s3-bucket/main.tf

variable provider {
   type = string
   default = "aws"
}
variable bucket_region {}
variable bucket_name {}

resource "aws_s3_bucket" "s3_bucket" {
   provider = var.provider
   region = var.bucket_region
   bucket = var.bucket_name
}

I've never explicitly set the provider like that though in a resource but based on the docs it might work.

Upvotes: 4

Related Questions