s3

The s3 state storage type lets a runner maintain Terraform state in S3 objects.

This state storage type results in the runner using a s3 backend (Terraform  / OpenTofu ). It is supported for all runner types. It requires that the runner has credentials to access AWS.

Follow the steps below to configure a state storage of type s3.

Example configuration

runner-config.yaml:

runner_configuration:
  ...
state_storage_configuration:
  type: s3
  bucket: my-bucket

Properties

Required

  • type: Always set to s3.
  • bucket: The name of the AWS S3 bucket to use. Since AWS S3 buckets are globally routable, you do not need to specify a region here.

Optional

  • path_prefix: An optional S3 object path prefix to use within the bucket. The final key for the state file will be (<path_prefix>/)<environment uuid>.tfstate. This may be useful if you are reusing the bucket between runners and will use IAM conditions to further restrict access.

You can set additional properties of the s3 backend using environment variables and files within the runner as documented in the s3 backend configuration (Terraform  / OpenTofu ). This allows you to configure the AWS credentials source and other optional fields. Unless otherwise configured, the underlying AWS SDK  will first check for access key, or web identity environment variables, then fall back to any mounted ~/.aws/credentials or ~/.aws/config file, before finally checking the local metadata API exposed in most ECS containers, EKS pods, or EC2 VMs. See the setup instructions below for recommended mechanisms based on the runner type.

Setup

Create an S3 bucket

We recommend that you use a dedicated S3 bucket for state storage. There is no required configuration for the bucket, however:

  • The bucket must not have public or broad access. State files frequently contain sensitive data which should not be accessible externally.
  • You may enable S3 replication for compliance, migration, or operational reasons. This will not affect the Platform Orchestrator.
  • You should enable versioning on the bucket to facilitate state rollback in the event of a misconfigured runner or destroyed environment.
  • You should not enable force-destroy on the bucket unless you have a reason to do so. Force-destroy allows the bucket to be deleted while it still contains state files which could result in permanent loss of all environment state.
  • AWS S3 encrypts bucket contents at rest by default, however you can configure server side encryption with a customer-owned KMS key if you wish.

For these reasons, we recommend that you use a bucket dedicated to storing Platform Orchestrator state files. You may reuse the same bucket between runners since state files are keyed by the unique identifier of the deployed environment.

You can create the bucket using the aws s3api create-bucket CLI command, through the aws_s3_bucket resource of the hashicorp/aws  TF provider, or through the AWS Console.

Setup an IAM role for the runner

There are a few ways you can ensure the runner has AWS credentials:

  1. Using a kubernetes-eks runner, use IAM roles for service accounts  to associate a role with the service account used by the runner pod. This populates either the local metadata APIs when pod identity or node roles are set, or web identity variables when using service account roles.
  2. Using a serverless-ecs runner, use either the execution_role_arn or the task_role_arn runner configuration property to specify a role. This populates the local metadata APIs.
  3. For non AWS-based runners, you may use platform-specific OIDC Federation to gain an AWS role. This can be configured by setting environment variables for the appropriate configuration to assume the role with web identity .
  4. As a last resort, you may generate values for the AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_REGION and set these as mounted secrets in your runner. This is not recommended as more secure federated credentials are usually available.

Permissions Required

You will need to grant appropriate permissions for the IAM role assumed by the runner. Because this role is exposed to all code in the runner, you should keep this policy as fine-grained as possible. The following policy allows the ECS runner to list, read, and write state files within the specific S3 bucket.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::<bucket_name>"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::<bucket_name>/<optional_path_prefix>/*"
        }
    ]
}

Set the state storage backend for the runner

Prepare the state storage configuration as part of a runner configuration as YAML:

state_storage_configuration:
  type: s3
  bucket: name-of-your-bucket
  path_prefix: optional/path

Or when using the Terraform or OpenTofu Provider:

state_storage_configuration = {
    type = "s3"
    s3_configuration = {
        bucket      = "name-of-your-bucket"
        path_prefix = "optional/path"
    }
}
Top