github.com/eliastor/durgaform@v0.0.0-20220816172711-d0ab2d17673e/website/docs/language/settings/backends/s3.mdx (about) 1 --- 2 page_title: 'Backend Type: s3' 3 description: Terraform can store state remotely in S3 and lock that state with DynamoDB. 4 --- 5 6 # S3 7 8 Stores the state as a given key in a given bucket on 9 [Amazon S3](https://aws.amazon.com/s3/). 10 This backend also supports state locking and consistency checking via 11 [Dynamo DB](https://aws.amazon.com/dynamodb/), which can be enabled by setting 12 the `dynamodb_table` field to an existing DynamoDB table name. 13 A single DynamoDB table can be used to lock multiple remote state files. Terraform generates key names that include the values of the `bucket` and `key` variables. 14 15 ~> **Warning!** It is highly recommended that you enable 16 [Bucket Versioning](https://docs.aws.amazon.com/AmazonS3/latest/userguide/manage-versioning-examples.html) 17 on the S3 bucket to allow for state recovery in the case of accidental deletions and human error. 18 19 ## Example Configuration 20 21 ```hcl 22 terraform { 23 backend "s3" { 24 bucket = "mybucket" 25 key = "path/to/my/key" 26 region = "us-east-1" 27 } 28 } 29 ``` 30 31 This assumes we have a bucket created called `mybucket`. The 32 Terraform state is written to the key `path/to/my/key`. 33 34 Note that for the access credentials we recommend using a 35 [partial configuration](/language/settings/backends/configuration#partial-configuration). 36 37 ### S3 Bucket Permissions 38 39 Terraform will need the following AWS IAM permissions on 40 the target backend bucket: 41 42 * `s3:ListBucket` on `arn:aws:s3:::mybucket` 43 * `s3:GetObject` on `arn:aws:s3:::mybucket/path/to/my/key` 44 * `s3:PutObject` on `arn:aws:s3:::mybucket/path/to/my/key` 45 * `s3:DeleteObject` on `arn:aws:s3:::mybucket/path/to/my/key` 46 47 This is seen in the following AWS IAM Statement: 48 49 ```json 50 { 51 "Version": "2012-10-17", 52 "Statement": [ 53 { 54 "Effect": "Allow", 55 "Action": "s3:ListBucket", 56 "Resource": "arn:aws:s3:::mybucket" 57 }, 58 { 59 "Effect": "Allow", 60 "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"], 61 "Resource": "arn:aws:s3:::mybucket/path/to/my/key" 62 } 63 ] 64 } 65 ``` 66 67 -> **Note:** AWS can control access to S3 buckets with either IAM policies 68 attached to users/groups/roles (like the example above) or resource policies 69 attached to bucket objects (which look similar but also require a `Principal` to 70 indicate which entity has those permissions). For more details, see Amazon's 71 documentation about 72 [S3 access control](https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html). 73 74 ### DynamoDB Table Permissions 75 76 If you are using state locking, Terraform will need the following AWS IAM 77 permissions on the DynamoDB table (`arn:aws:dynamodb:::table/mytable`): 78 79 * `dynamodb:GetItem` 80 * `dynamodb:PutItem` 81 * `dynamodb:DeleteItem` 82 83 This is seen in the following AWS IAM Statement: 84 85 ```json 86 { 87 "Version": "2012-10-17", 88 "Statement": [ 89 { 90 "Effect": "Allow", 91 "Action": [ 92 "dynamodb:GetItem", 93 "dynamodb:PutItem", 94 "dynamodb:DeleteItem" 95 ], 96 "Resource": "arn:aws:dynamodb:*:*:table/mytable" 97 } 98 ] 99 } 100 ``` 101 102 ## Data Source Configuration 103 104 To make use of the S3 remote state in another configuration, use the 105 [`terraform_remote_state` data 106 source](/language/state/remote-state-data). 107 108 ```hcl 109 data "terraform_remote_state" "network" { 110 backend = "s3" 111 config = { 112 bucket = "terraform-state-prod" 113 key = "network/terraform.tfstate" 114 region = "us-east-1" 115 } 116 } 117 ``` 118 119 The `terraform_remote_state` data source will return all of the root module 120 outputs defined in the referenced remote state (but not any outputs from 121 nested modules unless they are explicitly output again in the root). An 122 example output might look like: 123 124 ``` 125 data.terraform_remote_state.network: 126 id = 2016-10-29 01:57:59.780010914 +0000 UTC 127 addresses.# = 2 128 addresses.0 = 52.207.220.222 129 addresses.1 = 54.196.78.166 130 backend = s3 131 config.% = 3 132 config.bucket = terraform-state-prod 133 config.key = network/terraform.tfstate 134 config.region = us-east-1 135 elb_address = web-elb-790251200.us-east-1.elb.amazonaws.com 136 public_subnet_id = subnet-1e05dd33 137 ``` 138 139 ## Configuration 140 141 This backend requires the configuration of the AWS Region and S3 state storage. Other configuration, such as enabling DynamoDB state locking, is optional. 142 143 ### Credentials and Shared Configuration 144 145 !> **Warning:** We recommend using environment variables to supply credentials and other sensitive data. If you use `-backend-config` or hardcode these values directly in your configuration, Terraform will include these values in both the `.terraform` subdirectory and in plan files. Refer to [Credentials and Sensitive Data](/language/settings/backends/configuration#credentials-and-sensitive-data) for details. 146 147 The following configuration is required: 148 149 * `region` - (Required) AWS Region of the S3 Bucket and DynamoDB Table (if used). This can also be sourced from the `AWS_DEFAULT_REGION` and `AWS_REGION` environment variables. 150 151 The following configuration is optional: 152 153 * `access_key` - (Optional) AWS access key. If configured, must also configure `secret_key`. This can also be sourced from the `AWS_ACCESS_KEY_ID` environment variable, AWS shared credentials file (e.g. `~/.aws/credentials`), or AWS shared configuration file (e.g. `~/.aws/config`). 154 * `secret_key` - (Optional) AWS access key. If configured, must also configure `access_key`. This can also be sourced from the `AWS_SECRET_ACCESS_KEY` environment variable, AWS shared credentials file (e.g. `~/.aws/credentials`), or AWS shared configuration file (e.g. `~/.aws/config`). 155 * `iam_endpoint` - (Optional) Custom endpoint for the AWS Identity and Access Management (IAM) API. This can also be sourced from the `AWS_IAM_ENDPOINT` environment variable. 156 * `max_retries` - (Optional) The maximum number of times an AWS API request is retried on retryable failure. Defaults to 5. 157 * `profile` - (Optional) Name of AWS profile in AWS shared credentials file (e.g. `~/.aws/credentials`) or AWS shared configuration file (e.g. `~/.aws/config`) to use for credentials and/or configuration. This can also be sourced from the `AWS_PROFILE` environment variable. 158 * `shared_credentials_file` - (Optional) Path to the AWS shared credentials file. Defaults to `~/.aws/credentials`. 159 * `skip_credentials_validation` - (Optional) Skip credentials validation via the STS API. 160 * `skip_region_validation` - (Optional) Skip validation of provided region name. 161 * `skip_metadata_api_check` - (Optional) Skip usage of EC2 Metadata API. 162 * `sts_endpoint` - (Optional) Custom endpoint for the AWS Security Token Service (STS) API. This can also be sourced from the `AWS_STS_ENDPOINT` environment variable. 163 * `token` - (Optional) Multi-Factor Authentication (MFA) token. This can also be sourced from the `AWS_SESSION_TOKEN` environment variable. 164 165 #### Assume Role Configuration 166 167 The following configuration is optional: 168 169 * `assume_role_duration_seconds` - (Optional) Number of seconds to restrict the assume role session duration. 170 * `assume_role_policy` - (Optional) IAM Policy JSON describing further restricting permissions for the IAM Role being assumed. 171 * `assume_role_policy_arns` - (Optional) Set of Amazon Resource Names (ARNs) of IAM Policies describing further restricting permissions for the IAM Role being assumed. 172 * `assume_role_tags` - (Optional) Map of assume role session tags. 173 * `assume_role_transitive_tag_keys` - (Optional) Set of assume role session tag keys to pass to any subsequent sessions. 174 * `external_id` - (Optional) External identifier to use when assuming the role. 175 * `role_arn` - (Optional) Amazon Resource Name (ARN) of the IAM Role to assume. 176 * `session_name` - (Optional) Session name to use when assuming the role. 177 178 ### S3 State Storage 179 180 The following configuration is required: 181 182 * `bucket` - (Required) Name of the S3 Bucket. 183 * `key` - (Required) Path to the state file inside the S3 Bucket. When using a non-default [workspace](/language/state/workspaces), the state path will be `/workspace_key_prefix/workspace_name/key` (see also the `workspace_key_prefix` configuration). 184 185 The following configuration is optional: 186 187 * `acl` - (Optional) [Canned ACL](https://docs.aws.amazon.com/AmazonS3/latest/userguide/acl-overview.html#canned-acl) to be applied to the state file. 188 * `encrypt` - (Optional) Enable [server side encryption](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingServerSideEncryption.html) of the state file. 189 * `endpoint` - (Optional) Custom endpoint for the AWS S3 API. This can also be sourced from the `AWS_S3_ENDPOINT` environment variable. 190 * `force_path_style` - (Optional) Enable path-style S3 URLs (`https://<HOST>/<BUCKET>` instead of `https://<BUCKET>.<HOST>`). 191 * `kms_key_id` - (Optional) Amazon Resource Name (ARN) of a Key Management Service (KMS) Key to use for encrypting the state. Note that if this value is specified, Terraform will need `kms:Encrypt`, `kms:Decrypt` and `kms:GenerateDataKey` permissions on this KMS key. 192 * `sse_customer_key` - (Optional) The key to use for encrypting state with [Server-Side Encryption with Customer-Provided Keys (SSE-C)](https://docs.aws.amazon.com/AmazonS3/latest/userguide/ServerSideEncryptionCustomerKeys.html). This is the base64-encoded value of the key, which must decode to 256 bits. This can also be sourced from the `AWS_SSE_CUSTOMER_KEY` environment variable, which is recommended due to the sensitivity of the value. Setting it inside a terraform file will cause it to be persisted to disk in `terraform.tfstate`. 193 * `workspace_key_prefix` - (Optional) Prefix applied to the state path inside the bucket. This is only relevant when using a non-default workspace. Defaults to `env:`. 194 195 ### DynamoDB State Locking 196 197 The following configuration is optional: 198 199 * `dynamodb_endpoint` - (Optional) Custom endpoint for the AWS DynamoDB API. This can also be sourced from the `AWS_DYNAMODB_ENDPOINT` environment variable. 200 * `dynamodb_table` - (Optional) Name of DynamoDB Table to use for state locking and consistency. The table must have a partition key named `LockID` with type of `String`. If not configured, state locking will be disabled. 201 202 ## Multi-account AWS Architecture 203 204 A common architectural pattern is for an organization to use a number of 205 separate AWS accounts to isolate different teams and environments. For example, 206 a "staging" system will often be deployed into a separate AWS account than 207 its corresponding "production" system, to minimize the risk of the staging 208 environment affecting production infrastructure, whether via rate limiting, 209 misconfigured access controls, or other unintended interactions. 210 211 The S3 backend can be used in a number of different ways that make different 212 tradeoffs between convenience, security, and isolation in such an organization. 213 This section describes one such approach that aims to find a good compromise 214 between these tradeoffs, allowing use of 215 [Terraform's workspaces feature](/language/state/workspaces) to switch 216 conveniently between multiple isolated deployments of the same configuration. 217 218 Use this section as a starting-point for your approach, but note that 219 you will probably need to make adjustments for the unique standards and 220 regulations that apply to your organization. You will also need to make some 221 adjustments to this approach to account for _existing_ practices within your 222 organization, if for example other tools have previously been used to manage 223 infrastructure. 224 225 Terraform is an administrative tool that manages your infrastructure, and so 226 ideally the infrastructure that is used by Terraform should exist outside of 227 the infrastructure that Terraform manages. This can be achieved by creating a 228 separate _administrative_ AWS account which contains the user accounts used by 229 human operators and any infrastructure and tools used to manage the other 230 accounts. Isolating shared administrative tools from your main environments 231 has a number of advantages, such as avoiding accidentally damaging the 232 administrative infrastructure while changing the target infrastructure, and 233 reducing the risk that an attacker might abuse production infrastructure to 234 gain access to the (usually more privileged) administrative infrastructure. 235 236 ### Administrative Account Setup 237 238 Your administrative AWS account will contain at least the following items: 239 240 * One or more [IAM user](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users.html) 241 for system administrators that will log in to maintain infrastructure in 242 the other accounts. 243 * Optionally, one or more [IAM groups](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_groups.html) 244 to differentiate between different groups of users that have different 245 levels of access to the other AWS accounts. 246 * An [S3 bucket](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingBucket.html) 247 that will contain the Terraform state files for each workspace. 248 * A [DynamoDB table](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html#HowItWorks.CoreComponents.TablesItemsAttributes) 249 that will be used for locking to prevent concurrent operations on a single 250 workspace. 251 252 Provide the S3 bucket name and DynamoDB table name to Terraform within the 253 S3 backend configuration using the `bucket` and `dynamodb_table` arguments 254 respectively, and configure a suitable `workspace_key_prefix` to contain 255 the states of the various workspaces that will subsequently be created for 256 this configuration. 257 258 ### Environment Account Setup 259 260 For the sake of this section, the term "environment account" refers to one 261 of the accounts whose contents are managed by Terraform, separate from the 262 administrative account described above. 263 264 Your environment accounts will eventually contain your own product-specific 265 infrastructure. Along with this it must contain one or more 266 [IAM roles](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html) 267 that grant sufficient access for Terraform to perform the desired management 268 tasks. 269 270 ### Delegating Access 271 272 Each Administrator will run Terraform using credentials for their IAM user 273 in the administrative account. 274 [IAM Role Delegation](https://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_cross-account-with-roles.html) 275 is used to grant these users access to the roles created in each environment 276 account. 277 278 Full details on role delegation are covered in the AWS documentation linked 279 above. The most important details are: 280 281 * Each role's _Assume Role Policy_ must grant access to the administrative AWS 282 account, which creates a trust relationship with the administrative AWS 283 account so that its users may assume the role. 284 * The users or groups within the administrative account must also have a 285 policy that creates the converse relationship, allowing these users or groups 286 to assume that role. 287 288 Since the purpose of the administrative account is only to host tools for 289 managing other accounts, it is useful to give the administrative accounts 290 restricted access only to the specific operations needed to assume the 291 environment account role and access the Terraform state. By blocking all 292 other access, you remove the risk that user error will lead to staging or 293 production resources being created in the administrative account by mistake. 294 295 When configuring Terraform, use either environment variables or the standard 296 credentials file `~/.aws/credentials` to provide the administrator user's 297 IAM credentials within the administrative account to both the S3 backend _and_ 298 to Terraform's AWS provider. 299 300 Use conditional configuration to pass a different `assume_role` value to 301 the AWS provider depending on the selected workspace. For example: 302 303 ```hcl 304 variable "workspace_iam_roles" { 305 default = { 306 staging = "arn:aws:iam::STAGING-ACCOUNT-ID:role/Terraform" 307 production = "arn:aws:iam::PRODUCTION-ACCOUNT-ID:role/Terraform" 308 } 309 } 310 311 provider "aws" { 312 # No credentials explicitly set here because they come from either the 313 # environment or the global credentials file. 314 315 assume_role = { 316 role_arn = "${var.workspace_iam_roles[terraform.workspace]}" 317 } 318 } 319 ``` 320 321 If workspace IAM roles are centrally managed and shared across many separate 322 Terraform configurations, the role ARNs could also be obtained via a data 323 source such as [`terraform_remote_state`](/language/state/remote-state-data) 324 to avoid repeating these values. 325 326 ### Creating and Selecting Workspaces 327 328 With the necessary objects created and the backend configured, run 329 `terraform init` to initialize the backend and establish an initial workspace 330 called "default". This workspace will not be used, but is created automatically 331 by Terraform as a convenience for users who are not using the workspaces 332 feature. 333 334 Create a workspace corresponding to each key given in the `workspace_iam_roles` 335 variable value above: 336 337 ``` 338 $ terraform workspace new staging 339 Created and switched to workspace "staging"! 340 341 ... 342 343 $ terraform workspace new production 344 Created and switched to workspace "production"! 345 346 ... 347 ``` 348 349 Due to the `assume_role` setting in the AWS provider configuration, any 350 management operations for AWS resources will be performed via the configured 351 role in the appropriate environment AWS account. The backend operations, such 352 as reading and writing the state from S3, will be performed directly as the 353 administrator's own user within the administrative account. 354 355 ``` 356 $ terraform workspace select staging 357 $ terraform apply 358 ... 359 ``` 360 361 ### Running Terraform in Amazon EC2 362 363 Teams that make extensive use of Terraform for infrastructure management 364 often [run Terraform in automation](https://learn.hashicorp.com/tutorials/terraform/automate-terraform?in=terraform/automation&utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) 365 to ensure a consistent operating environment and to limit access to the 366 various secrets and other sensitive information that Terraform configurations 367 tend to require. 368 369 When running Terraform in an automation tool running on an Amazon EC2 instance, 370 consider running this instance in the administrative account and using an 371 [instance profile](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html) 372 in place of the various administrator IAM users suggested above. An IAM 373 instance profile can also be granted cross-account delegation access via 374 an IAM policy, giving this instance the access it needs to run Terraform. 375 376 To isolate access to different environment accounts, use a separate EC2 377 instance for each target account so that its access can be limited only to 378 the single account. 379 380 Similar approaches can be taken with equivalent features in other AWS compute 381 services, such as ECS. 382 383 ### Protecting Access to Workspace State 384 385 In a simple implementation of the pattern described in the prior sections, 386 all users have access to read and write states for all workspaces. In many 387 cases it is desirable to apply more precise access constraints to the 388 Terraform state objects in S3, so that for example only trusted administrators 389 are allowed to modify the production state, or to control _reading_ of a state 390 that contains sensitive information. 391 392 Amazon S3 supports fine-grained access control on a per-object-path basis 393 using IAM policy. A full description of S3's access control mechanism is 394 beyond the scope of this guide, but an example IAM policy granting access 395 to only a single state object within an S3 bucket is shown below: 396 397 ```json 398 { 399 "Version": "2012-10-17", 400 "Statement": [ 401 { 402 "Effect": "Allow", 403 "Action": "s3:ListBucket", 404 "Resource": "arn:aws:s3:::myorg-terraform-states" 405 }, 406 { 407 "Effect": "Allow", 408 "Action": ["s3:GetObject", "s3:PutObject"], 409 "Resource": "arn:aws:s3:::myorg-terraform-states/myapp/production/tfstate" 410 } 411 ] 412 } 413 ``` 414 415 It is also possible to apply fine-grained access control to the DynamoDB 416 table used for locking. When Terraform puts the state lock in place during `terraform plan`, it stores the full state file as a document and sets the s3 object key as the partition key for the document. After the state lock is released, Terraform places a digest of the updated state file in DynamoDB. The key is similar to the one for the original state file, but is suffixed with `-md5`. 417 418 The example below shows a simple IAM policy that allows the backend operations role to perform these operations: 419 420 ```json 421 { 422 "Version": "2012-10-17", 423 "Statement": [ 424 { 425 "Effect" : "Allow", 426 "Action" : [ 427 "dynamodb:DeleteItem", 428 "dynamodb:GetItem", 429 "dynamodb:PutItem", 430 "dynamodb:Query", 431 "dynamodb:UpdateItem" 432 ], 433 "Resource" : ["arn:aws:dynamodb:*:*:table/myorg-state-lock-table"], 434 "Condition" : { 435 "ForAllValues:StringEquals" : { 436 "dynamodb:LeadingKeys" : [ 437 "myorg-terraform-states/myapp/production/tfstate", // during a state lock the full state file is stored with this key 438 "myorg-terraform-states/myapp/production/tfstate-md5" // after the lock is released a hash of the statefile's contents are stored with this key 439 ] 440 } 441 } 442 } 443 ] 444 } 445 ``` 446 447 Refer to the [AWS documentation on DynamoDB fine-grained locking](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/specifying-conditions.html) for more details. 448 449 ### Configuring Custom User-Agent Information 450 451 Note this feature is optional and only available in Terraform v0.13.1+. 452 453 By default, the underlying AWS client used by the Terraform AWS Provider creates requests with User-Agent headers including information about Terraform and AWS Go SDK versions. To provide additional information in the User-Agent headers, the `TF_APPEND_USER_AGENT` environment variable can be set and its value will be directly added to HTTP requests. e.g. 454 455 ```sh 456 $ export TF_APPEND_USER_AGENT="JenkinsAgent/i-12345678 BuildID/1234 (Optional Extra Information)" 457 ```