Hi,
I have been trying to setup and configure an AWS S3 bucket for the terraform remote state file which is best practice. So I can create the S3 bucket with the following code:
v0.10.7
main.tf
resource "aws_s3_bucket" "terraform-state" {
bucket = "${var.s3bucket}"
acl = "private"
versioning {
enabled = true
}
lifecycle {
prevent_destroy = true
}
}
output.tf
output "s3_bucket_arn" {
value = "${aws_s3_bucket.terraform-state.arn}"
}
var_values.tfvars
access_key = "xxxxxxxxxxxxxxxxx"
secret_key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
region = "eu-west-1"
s3bucket = "bucket-name"
variables.tf
provider "aws" {
access_key = "${var.access_key}"
secret_key = "${var.secret_key}"
region = "${var.region}"
}
variable "access_key" {
description = "This is the AWS access key"
}
variable "secret_key" {
description = "This is the AWS secret key"
}
variable "region" {
description = "The default AWS region for the resource provisioning"
}
variable "s3bucket" {
description = "AWS S3 bucket where the terraform.tfstate is located"
}
Then you would normally run the following to configure the terraform to use S3 bucket this is no longer in the terraform version I'm using (v0.10.7):
terraform remote config \
-backend=s3 \
-backend-config="tf-remote-state-storage" \
-backend-config="key=terraform.tfstate" \
-backend-config="region=eu-west-1" \
-backend-config="encrypt=true"
So I have been following the terraform website and using the following bit of code:
Note: As when I use resource "terraform_remote_state" "trss" I get the following warning message:
There are warnings related to your configuration. If no errors occurred,
Terraform will continue despite these warnings. It is a good idea to resolve
these warnings in the near future.
Warnings:
* terraform_remote_state.trss: using terraform_remote_state as a resource is deprecated; consider using the data source instead
So I'm now using the following bit of code:
trss.tf
data "terraform_remote_state" "trss" {
backend = "s3"
config {
bucket = "${var.s3bucket}"
key = "terraform.tfstate"
region = "${var.region}"
encrypt = true
}
}
But I keep getting the following error:
Error refreshing state: 1 error(s) occurred:
data.terraform_remote_state.trss: 1 error(s) occurred:
data.terraform_remote_state.trss: data.terraform_remote_state.trss: error initializing backend: No valid credential sources found for AWS Provider.
Please see https://terraform.io/docs/providers/aws/index.html for more information on
providing credentials for the AWS Provider
There is nothing wrong with the access key or the secret key as the bucket is created. Also tested them with another terraform bit of code and works no problem.
terraform_remote_state.trss: Creating...
backend: "" => "s3"
config.%: "" => "4"
config.bucket: "" => "sbn-tf-remote-state-storage"
config.encrypt: "" => "1"
config.key: "" => "terraform.tfstate"
config.region: "" => "eu-west-1"
environment: "" => "default"
aws_s3_bucket.sbn-terraform-state: Creating...
acceleration_status: "" => "<computed>"
acl: "" => "private"
arn: "" => "<computed>"
bucket: "" => "sbn-tf-remote-state-storage"
bucket_domain_name: "" => "<computed>"
force_destroy: "" => "false"
hosted_zone_id: "" => "<computed>"
region: "" => "<computed>"
request_payer: "" => "<computed>"
versioning.#: "" => "1"
versioning.0.enabled: "" => "true"
versioning.0.mfa_delete: "" => "false"
website_domain: "" => "<computed>"
website_endpoint: "" => "<computed>"
aws_s3_bucket.sbn-terraform-state: Creation complete after 6s (ID: sbn-tf-remote-state-storage)
So then I added the following to the code:
data "terraform_remote_state" "trss" {
backend = "s3"
config {
bucket = "${var.s3bucket}"
key = "trss/terraform.tfstate"
region = "${var.region}"
encrypt = true
access_key = "${var.access_key}"
secret_key = "${var.secret_key}"
}
}
I have to run the two bits of code separate, the first part creates the bucket and then I run the second bit of code the above data "terraform_remote_state" "trss" and now get the following:
$ terraform plan -var-file var_values.tfvars
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
data.terraform_remote_state.trss: Refreshing state...
------------------------------------------------------------------------
No changes. Infrastructure is up-to-date.
This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, no
actions need to be performed.
$ terraform apply -var-file var_values.tfvars
data.terraform_remote_state.trss: Refreshing state...
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
The file is not being created in the S3 bucket!!!!
So I added the data "terraform_remote_state" "trss" to a config setup of a single server as follows:
resource "aws_instance" "example" {
# Ubuntu Server 16.04 LTS (HVM), SSD Volume Type in eu-west-1.
ami = "ami-785db401"
instance_type = "t2.micro"
availability_zone = "eu-west-1a"
vpc_security_group_ids = ["${aws_security_group.instance.id}"]
user_data = <<-EOF
#!/bin/bash
echo "Hello, World" > index.html
nohup busybox httpd -f -p "${var.server_port}" &
EOF
tags {
Name = "TF-VM01"
}
}
resource "aws_security_group" "instance" {
name = "TF-VM01-instance"
# Inbound HTTP from anywhere.
ingress {
from_port = "${var.server_port}"
to_port = "${var.server_port}"
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
data "terraform_remote_state" "trss" {
backend = "s3"
config {
bucket = "${var.s3bucket}"
key = "trss/terraform.tfstate"
region = "${var.region}"
encrypt = true
access_key = "${var.access_key}"
secret_key = "${var.secret_key}"
}
}
But still no tfstate file in the S3 bucket............!!
Any ideas on how this is done now? or the reason to what I'm doing wrong here?
Thanks
Hi @joda10! Sorry things aren't working as expected here.
The data "terraform_remote_state" block is used to _read_ the state generated by _another_ configuration, rather than to configure remote state for the _current_ configuration.
The equivalent configuration to your terraform remote config command is the following:
terraform {
backend "s3" {
bucket = "tf-remote-state-storage"
key = "terraform.tfstate"
region = "eu-west-1"
encrypt = true
}
}
After you add this to configuration, you must run terraform init to initialize the new backend. If you have any existing local state at this point, Terraform will offer to migrate it to S3.
If you still need to set some of your settings on the command line, rather than checking them in to version control as part of configuration, you can use the -backend-config argument to terraform init as a replacement for the argument of the same name on terraform remote config; having the backend "s3" block in configuration -- possibly empty -- is required, though.
The 0.8-to-0.9 upgrade guide covers some more detail on this transition. Unfortunately some parts of it may be outdated since the init command continued to evolve in 0.10, but broadly-speaking the content there should still be suitable.
Hi apparentlymart,
So I have added the code above and change where I needed. But when I run the terraform init I get the following error now:
Error loading backend config: 1 error(s) occurred:
* terraform.backend: configuration cannot contain interpolations
The backend configuration is loaded by Terraform extremely early, before
the core of Terraform can be initialized. This is necessary because the backend
dictates the behavior of that core. The core is what handles interpolation
processing. Because of this, interpolations cannot be used in backend
configuration.
If you'd like to parameterize backend configuration, we recommend using
partial configuration with the "-backend-config" flag to "terraform init".
Still not to sure what is going wrong.
Thanks.
Just as before (when these settings were provided on the terraform remote config command line) it is not allowed to use interpolation expressions in this configuration block, for the reasons given in that error message.
If parts of the backend config need to vary per run then you should omit them from the configuration and then pass them to terraform init as described in that error message:
terraform {
backend "s3" {
key = "terraform.tfstate"
encrypt = true
}
}
$ terraform init -backend-config="region=eu-west-1" -backend-config="bucket=tf-remote-state-storage"
Hi,
Just tested this again and still no joy..... So I have created the bucket and now created a file on its own called:
main.tf
terraform {
backend "s3" {
key = "trss/terraform.tfstate"
encrypt = true
}
}
As above and then I have the other files: var_values.tfvars which has the access, secret keys and region and variables.tf. These files can be view above. Then I run the command below:
$ terraform init -backend-config="region=eu-west-1" -backend-config="bucket=tf-remote-state-storage"
This is the error message I'm getting now:
Initializing the backend...
Error configuring the backend "s3": No valid credential sources found for AWS Provider.
Please see https://terraform.io/docs/providers/aws/index.html for more information on
providing credentials for the AWS Provider
Please update the configuration in your Terraform files to fix this error
then run this command again.
So I went to the web link and it shows how to setup the following:
provider "aws" {
access_key = "xxxxxxxxxxxxxxxxxxxxxxxx"
secret_key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
region = "eu-west-1"
}
Which I'm doing already using variables. So to test this I added the above to the main.tf file and now this is the only file in the directory. This is how the file looks now:
provider "aws" {
access_key = "xxxxxxxxxxxxxxxxxxxxxxxx"
secret_key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
region = "eu-west-1"
}
terraform {
backend "s3" {
key = "trss/terraform.tfstate"
encrypt = true
}
}
So now I get:
Initializing the backend...
Error configuring the backend "s3": No valid credential sources found for AWS Provider.
Please see https://terraform.io/docs/providers/aws/index.html for more information on
providing credentials for the AWS Provider
Please update the configuration in your Terraform files to fix this error
then run this command again
So then I tried terraform init and got the following:
Initializing the backend...
bucket
The name of the S3 bucket
Enter a value: sbn-tf-remote-state-storage
region
The region of the S3 bucket.
Enter a value: eu-west-1
Error configuring the backend "s3": No valid credential sources found for AWS Provider.
Please see https://terraform.io/docs/providers/aws/index.html for more information on
providing credentials for the AWS Provider
Please update the configuration in your Terraform files to fix this error
then run this command again.
I've check the access & secret keys which are good.
Not sure where I'm going wrong here. Your help is much appreciated.
I have it working as follows:
terraform init and terraform plan provider "aws" {
region = "${var.aws_region}"
}
terraform {
backend "s3" {
region = "us-east-1"
bucket = "tf-state"
key = "terraform.tfstate"
encrypt = true
}
}
Hey albertvdv,
Thanks for your response....... so I have now downloaded in the bash session the AWS CLI and then setup the AWS profile as follows:
$ aws configure
AWS Access Key ID [None]: xxxxxxxxxxxxxxxxxx
AWS Secret Access Key [None]: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Default region name [None]: eu-west-1
Default output format [None]:
Then change the terraform file as follows:
main.tf
provider "aws" {
region = "eu-west-1"
}
terraform {
backend "s3" {
region = "eu-west-1"
bucket = "tf-remote-state-storage"
key = "trss/terraform.tfstate"
encrypt = true
}
}
Now the output I get is:
$ terraform init
Initializing the backend...
Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.
Initializing provider plugins...
- Checking for available provider plugins on https://releases.hashicorp.com...
- Downloading plugin for provider "aws" (1.1.0)...
The following providers do not have any version constraints in configuration,
so the latest version was installed.
To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.
* provider.aws: version = "~> 1.1"
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
------------------------------------------------------------------------
No changes. Infrastructure is up-to-date.
This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, no
actions need to be performed.
$ terraform apply
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Now looking at the AWS S3 bucket I now have the file terraform.tfstate as expected.
I will now test with a deployment to confirm this is working as expected.
Thanks again to both of you for your support!
J
So I just tested the terraform.tfstate file which is not updating after deployment!
So I added this to a little test deployment:
data "terraform_remote_state" "trss" {
backend = "s3"
config {
bucket = "${var.s3bucket}"
key = "trss/terraform.tfstate"
region = "${var.region}"
encrypt = true
}
}
I have checked the file and it is still the same as it was after the tfstate config!
I can see the local file is updating and has this in it:
"data.terraform_remote_state.trss": {
"type": "terraform_remote_state",
"depends_on": [],
"primary": {
"id": "2017-10-27 14:17:18.9415246 +0000 UTC",
"attributes": {
"backend": "s3",
"config.%": "4",
"config.bucket": "tf-remote-state-storage",
"config.encrypt": "1",
"config.key": "trss/terraform.tfstate",
"config.region": "eu-west-1",
"environment": "default",
"id": "2017-10-27 14:17:18.9415246 +0000 UTC"
But the file in the S3 bucket looks like this:
{
"version": 3,
"terraform_version": "0.10.7",
"serial": 1,
"lineage": "a01b68c2-4031-44c4-9d44-33566b65c071",
"modules": [
{
"path": [
"root"
],
"outputs": {},
"resources": {},
"depends_on": []
}
]
}
Here is the Bash session output:
$ terraform plan -var-file var_values.tfvars
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
data.terraform_remote_state.trss: Refreshing state...
------------------------------------------------------------------------
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
+ aws_instance.example
id: <computed>
ami: "ami-785db401"
associate_public_ip_address: <computed>
availability_zone: "eu-west-1a"
ebs_block_device.#: <computed>
ephemeral_block_device.#: <computed>
instance_state: <computed>
instance_type: "t2.micro"
ipv6_address_count: <computed>
ipv6_addresses.#: <computed>
key_name: <computed>
network_interface.#: <computed>
network_interface_id: <computed>
placement_group: <computed>
primary_network_interface_id: <computed>
private_dns: <computed>
private_ip: <computed>
public_dns: <computed>
public_ip: <computed>
root_block_device.#: <computed>
security_groups.#: <computed>
source_dest_check: "true"
subnet_id: <computed>
tags.%: "1"
tags.Name: "TF-VM01"
tenancy: <computed>
user_data: "4430fd6498339061effa6d27ccf341a1e94569d7"
volume_tags.%: <computed>
vpc_security_group_ids.#: <computed>
+ aws_security_group.instance
id: <computed>
description: "Managed by Terraform"
egress.#: <computed>
ingress.#: "1"
ingress.516175195.cidr_blocks.#: "1"
ingress.516175195.cidr_blocks.0: "0.0.0.0/0"
ingress.516175195.description: ""
ingress.516175195.from_port: "8080"
ingress.516175195.ipv6_cidr_blocks.#: "0"
ingress.516175195.protocol: "tcp"
ingress.516175195.security_groups.#: "0"
ingress.516175195.self: "false"
ingress.516175195.to_port: "8080"
name: "TF-VM01-instance"
owner_id: <computed>
vpc_id: <computed>
Plan: 2 to add, 0 to change, 0 to destroy.
------------------------------------------------------------------------
Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.
$ terraform apply -var-file var_values.tfvars
data.terraform_remote_state.trss: Refreshing state...
aws_security_group.instance: Creating...
description: "" => "Managed by Terraform"
egress.#: "" => "<computed>"
ingress.#: "" => "1"
ingress.516175195.cidr_blocks.#: "" => "1"
ingress.516175195.cidr_blocks.0: "" => "0.0.0.0/0"
ingress.516175195.description: "" => ""
ingress.516175195.from_port: "" => "8080"
ingress.516175195.ipv6_cidr_blocks.#: "" => "0"
ingress.516175195.protocol: "" => "tcp"
ingress.516175195.security_groups.#: "" => "0"
ingress.516175195.self: "" => "false"
ingress.516175195.to_port: "" => "8080"
name: "" => "TF-VM01-instance"
owner_id: "" => "<computed>"
vpc_id: "" => "<computed>"
aws_security_group.instance: Creation complete after 1s (ID: sg-2176b05a)
aws_instance.example: Creating...
ami: "" => "ami-785db401"
associate_public_ip_address: "" => "<computed>"
availability_zone: "" => "eu-west-1a"
ebs_block_device.#: "" => "<computed>"
ephemeral_block_device.#: "" => "<computed>"
instance_state: "" => "<computed>"
instance_type: "" => "t2.micro"
ipv6_address_count: "" => "<computed>"
ipv6_addresses.#: "" => "<computed>"
key_name: "" => "<computed>"
network_interface.#: "" => "<computed>"
network_interface_id: "" => "<computed>"
placement_group: "" => "<computed>"
primary_network_interface_id: "" => "<computed>"
private_dns: "" => "<computed>"
private_ip: "" => "<computed>"
public_dns: "" => "<computed>"
public_ip: "" => "<computed>"
root_block_device.#: "" => "<computed>"
security_groups.#: "" => "<computed>"
source_dest_check: "" => "true"
subnet_id: "" => "<computed>"
tags.%: "" => "1"
tags.Name: "" => "TF-VM01"
tenancy: "" => "<computed>"
user_data: "" => "4430fd6498339061effa6d27ccf341a1e94569d7"
volume_tags.%: "" => "<computed>"
vpc_security_group_ids.#: "" => "1"
vpc_security_group_ids.2682271318: "" => "sg-2176b05a"
aws_instance.example: Still creating... (10s elapsed)
aws_instance.example: Still creating... (20s elapsed)
aws_instance.example: Creation complete after 23s (ID: i-06b8d77895f6ddea7)
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Outputs:
public_ip = xx.xx.xx.xx
Am I missing something here?
I have got this working now by creating the following file:
backend.tf
data "terraform_remote_state" "trss" {
backend = "s3"
config {
bucket = "${var.s3bucket}"
key = "terraform.tfstate"
region = "${var.region}"
encrypt = true
}
}
terraform {
backend "s3" {
bucket = "tf-remote-state-storage"
key = "terraform.tfstate"
region = "eu-west-1"
encrypt = true
}
}
Just to be clear you can only use variables in the data part of the code. in the terraform part of the code you must hardcode the variables/values or you will end up with an error message as follows:
$ terraform init
Initializing the backend...
Error loading backend config: 1 error(s) occurred:
* terraform.backend: configuration cannot contain interpolations
The backend configuration is loaded by Terraform extremely early, before
the core of Terraform can be initialized. This is necessary because the backend
dictates the behavior of that core. The core is what handles interpolation
processing. Because of this, interpolations cannot be used in backend
configuration.
If you'd like to parameterize backend configuration, we recommend using
partial configuration with the "-backend-config" flag to "terraform init".
When it's working and you have hardcoded your variables/values you will get the following:
$ terraform init
Initializing the backend...
Do you want to copy state from "local" to "s3"?
Pre-existing state was found in "local" while migrating to "s3". An existing
non-empty state exists in "s3". The two states have been saved to temporary
files that will be removed after responding to this query.
One ("local"): /tmp/terraform440398147/1-local.tfstate
Two ("s3"): /tmp/terraform440398147/2-s3.tfstate
Do you want to copy the state from "local" to "s3"? Enter "yes" to copy
and "no" to start with the existing state in "s3".
Enter a value: yes
Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.
Initializing provider plugins...
The following providers do not have any version constraints in configuration,
so the latest version was installed.
To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.
* provider.aws: version = "~> 1.1"
* provider.terraform: version = "~> 1.0"
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
At this point you can check the .tfstate file in the S3 bucket and make sure the time stamp has changed.
Now all you need to do is run the terraform plan & terraform apply job done....!!
If you're using Terraform workspaces and s3 don't forget to put use the "envronment" parameter in data "terraform_remote_state".
Without this the url that gets constructed won't match the key of the state file in the bucket and you'll get a message like:
Resource 'data.terraform_remote_state.core-network' does not have attribute 'vpcid' for variable 'data.terraform_remote_state.core-network.vpcid
@curleighbraces the only thing that has worked for me so far is @joda10 above comments. I have tried workspace but it does exactly what he pointed out above. Would love to use this without hardcoding.
@joda10 however it does work as you have stated I am not really able to use this method because it's too static, I also need to use local workspaces. Are there version restrictions or something here? I don't get it. I can second all of what @joda10 has been through here.
This:
data "terraform_remote_state" "network" {
backend = "s3"
environment = "${terraform.workspace}"
config {
bucket = "${var.state_bucket}"
key = "terraform.tfstate"
region = "${var.region}"
}
}
Only gives this on the s3 bucket state files:
{
"version": 3,
"serial": 1,
"lineage": "c8f404eb-ea2a-4290-a04d-3db53875cc38",
"modules": [
{
"path": [
"root"
],
"outputs": {},
"resources": {},
"depends_on": []
}
]
}
Locally my state files are in their respective workspace. What else could I check to make sure the files are being uploaded?
I don't see anything about environment here (https://www.terraform.io/docs/backends/types/s3.html). It doesn't look like it is part of the backend attributes? Is documentation out of date?
This is what I currently use.
```# Providers
provider "aws" {
region = "${data.terraform_remote_state.config.default_region}"
profile = "${data.terraform_remote_state.config.run_env}"
}
terraform {
required_version = ">=0.11.0"
backend "s3" {
bucket = "cv-terraform-backend"
key = "app_iam/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "cv-terraform-state"
workspace_key_prefix = "terraform-state"
}
}
data "terraform_remote_state" "config" {
backend = "s3"
config {
bucket = "cv-terraform-backend"
key = "terraform-state/${var.workspace}-config/config/terraform.tfstate"
region = "us-east-1"
}
}
```
FYI: If you ended up here because you suddenly get
Error configuring the backend "s3": No valid credential sources found for AWS Provider.
when you switch to using remote state in S3, you might have made the same mistake as me. In my .aws/credentials file I had wrongly written
[profile mycompany]
aws_access_key_id = AKIAxxxxxxxxxx
aws_secret_access_key = yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
It should instead read
[mycompany]
aws_access_key_id = AKIAxxxxxxxxxx
aws_secret_access_key = yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
Why this only shows up when using S3 is mysterious.
This terraform module and project might be helpful to some:
https://github.com/samstav/terraform-aws-backend
This module helps you bootstrap your terraform project with an aws backend. Includes instructions for new projects as well as existing projects.
I'm going to lock this issue because it has been closed for _30 days_ โณ. This helps our maintainers find and focus on the active issues.
If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.
Most helpful comment
Hey albertvdv,
Thanks for your response....... so I have now downloaded in the bash session the AWS CLI and then setup the AWS profile as follows:
Then change the terraform file as follows:
main.tf
Now the output I get is:
Now looking at the AWS S3 bucket I now have the file terraform.tfstate as expected.
I will now test with a deployment to confirm this is working as expected.
Thanks again to both of you for your support!
J