diff --git a/website/docs/backends/types/s3.html.md b/website/docs/backends/types/s3.html.md index 13049c2c3b..610ee74356 100644 --- a/website/docs/backends/types/s3.html.md +++ b/website/docs/backends/types/s3.html.md @@ -147,3 +147,221 @@ The following configuration options or environment variables are supported: * `skip_region_validation` - (Optional) Skip validation of provided region name. * `skip_requesting_account_id` - (Optional) Skip requesting the account ID. * `skip_metadata_api_check` - (Optional) Skip the AWS Metadata API check. + +## Multi-account AWS Architecture + +A common architectural pattern is for an organization to use a number of +separate AWS accounts to isolate different teams and environments. For example, +a "staging" system will often be deployed into a separate AWS account than +its corresponding "production" system, to minimize the risk of the staging +environment affecting production infrastructure, whether via rate limiting, +misconfigured access controls, or other unintended interactions. + +The S3 backend can be used in a number of different ways that make different +tradeoffs between convenience, security, and isolation in such an organization. +This section describes one such approach that aims to find a good compromise +between these tradeoffs, allowing use of +[Terraform's workspaces feature](/docs/state/workspaces.html) to switch +conveniently between multiple isolated deployments of the same configuration. + +Use this section as a starting-point for your approach, but note that +you will probably need to make adjustments for the unique standards and +regulations that apply to your organization. You will also need to make some +adjustments to this approach to account for _existing_ practices within your +organization, if for example other tools have previously been used to manage +infrastructure. + +Terraform is an administrative tool that manages your infrastructure, and so +ideally the infrastructure that is used by Terraform should exist outside of +the infrastructure that Terraform manages. This can be achieved by creating a +separate _administrative_ AWS account which contains the user accounts used by +human operators and any infrastructure and tools used to manage the the other +accounts. Isolating shared administrative tools from your main environments +has a number of advantages, such as avoiding accidentally damaging the +administrative infrastructure while changing the target infrastructure, and +reducing the risk that an attacker might abuse production infrastructure to +gain access to the (usually more privileged) administrative infrastructure. + +### Administrative Account Setup + +Your administrative AWS account will contain at least the following items: + +* One or more [IAM user](http://docs.aws.amazon.com/IAM/latest/UserGuide/id_users.html) + for system administrators that will log in to maintain infrastructure in + the other accounts. +* Optionally, one or more [IAM groups](http://docs.aws.amazon.com/IAM/latest/UserGuide/id_groups.html) + to differentiate between different groups of users that have different + levels of access to the other AWS accounts. +* An [S3 bucket](http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html) + that will contain the Terraform state files for each workspace. +* A [DynamoDB table](http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.CoreComponents.html#HowItWorks.CoreComponents.TablesItemsAttributes) + that will be used for locking to prevent concurrent operations on a single + workspace. + +Provide the S3 bucket name and DynamoDB table name to Terraform within the +S3 backend configuration using the `bucket` and `lock_table` arguments +respectively, and configure a suitable `workspace_key_prefix` to contain +the states of the various workspaces that will subsequently be created for +this configuration. + +### Environment Account Setup + +For the sake of this section, the term "environment account" refers to one +of the accounts whose contents are managed by Terraform, separate from the +administrative account described above. + +Your environment accounts will eventually contain your own product-specific +infrastructure. Along with this it must contain one or more +[IAM roles](http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html) +that grant sufficient access for Terraform to perform the desired management +tasks. + +### Delegating Access + +Each Administrator will run Terraform using credentials for their IAM user +in the administrative account. +[IAM Role Delegation](http://docs.aws.amazon.com/IAM/latest/UserGuide/tutorial_cross-account-with-roles.html) +is used to grant these users access to the roles created in each environment +account. + +Full details on role delegation are covered in the AWS documentation linked +above. The most important details are: + +* Each role's _Assume Role Policy_ must grant access to the administrative AWS + account, which creates a trust relationship with the administrative AWS + account so that its users may assume the role. +* The users or groups within the administrative account must also have a + policy that creates the converse relationship, allowing these users or groups + to assume that role. + +Since the purpose of the administrative account is only to host tools for +managing other accounts, it is useful to give the administrative accounts +restricted access only to the specific operations needed to assume the +environment account role and access the Terraform state. By blocking all +other access, you remove the risk that user error will lead to staging or +production resources being created in the administrative account by mistake. + +When configuring Terraform, use either environment variables or the standard +credentials file `~/.aws/credentials` to provide the administrator user's +IAM credentials within the administrative account to both the S3 backend _and_ +to Terraform's AWS provider. + +Use conditional configuration to pass a different `assume_role` value to +the AWS provider depending on the selected workspace. For example: + +```hcl +variable "workspace_iam_roles" { + default = { + staging = "arn:aws:iam::STAGING-ACCOUNT-ID:role/Terraform" + production = "arn:aws:iam::PRODUCTION-ACCOUNT-ID:role/Terraform" + } +} + +provider "aws" { + # No credentials explicitly set here because they come from either the + # environment or the global credentials file. + + assume_role = "${var.workspace_iam_roles[terraform.workspace]}" +} +``` + +If workspace IAM roles are centrally managed and shared across many separate +Terraform configurations, the role ARNs could also be obtained via a data +source such as [`terraform_remote_state`](/docs/providers/terraform/d/remote_state.html) +to avoid repeating these values. + +### Creating and Selecting Workspaces + +With the necessary objects created and the backend configured, run +`terraform init` to initialize the backend and establish an initial workspace +called "default". This workspace will not be used, but is created automatically +by Terraform as a convenience for users who are not using the workspaces +feature. + +Create a workspace corresponding to each key given in the `workspace_iam_roles` +variable value above: + +``` +$ terraform worspace new staging +Created and switched to workspace "staging"! + +... + +$ terraform workspace new production +Created and switched to workspace "production"! + +... +``` + +Due to the `assume_role` setting in the AWS provider configuration, any +management operations for AWS resources will be performed via the configured +role in the appropriate environment AWS account. The backend operations, such +as reading and writing the state from S3, will be performed directly as the +administrator's own user within the administrative account. + +``` +$ terraform workspace select staging +$ terraform apply +... +``` + +### Running Terraform in Amazon EC2 + +Teams that make extensive use of Terraform for infrastructure management +often [run Terraform in automation](/guides/running-terraform-in-automation.html) +to ensure a consistent operating environment and to limit access to the +various secrets and other sensitive information that Terraform configurations +tend to require. + +When running Terraform in an automation tool running on an Amazon EC2 instance, +consider running this instance in the administrative account and using an +[instance profile](http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html) +in place of the various administrator IAM users suggested above. An IAM +instance profile can also be granted cross-account delegation access via +an IAM policy, giving this instance the access it needs to run Terraform. + +To isolate access to different environment accounts, use a separate EC2 +instance for each target account so that its access can be limited only to +the single account. + +Similar approaches can be taken with equivalent features in other AWS compute +services, such as ECS. + +### Protecting Access to Workspace State + +In a simple implementation of the pattern described in the prior sections, +all users have access to read and write states for all workspaces. In many +cases it is desirable to apply more precise access constraints to the +Terraform state objects in S3, so that for example only trusted administrators +are allowed to modify the production state, or to control _reading_ of a state +that contains sensitive information. + +Amazon S3 supports fine-grained access control on a per-object-path basis +using IAM policy. A full description of S3's access control mechanism is +beyond the scope of this guide, but an example IAM policy granting access +to only a single state object within an S3 bucket is shown below: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "s3:ListBucket", + "Resource": "arn:aws:s3:::myorg-terraform-states" + }, + { + "Effect": "Allow", + "Action": ["s3:GetObject", "s3:PutObject"], + "Resource": "arn:aws:s3:::myorg-terraform-states/myapp/production/tfstate" + } + ] +} +``` + +It is not possible to apply such fine-grained access control to the DynamoDB +table used for locking, so it is possible for any user with Terraform access +to lock any workspace state, even if they do not have access to read or write +that state. If a malicious user has such access they could block attempts to +use Terraform against some or all of your workspaces as long as locking is +enabled in the backend configuration.