> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cloudcapital.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Terraform Setup for the Optimization Role

> For customers who manage all AWS infrastructure via Terraform: create the Cloud Capital Optimization role without using the CloudFormation template.

Cloud Capital normally provisions the [Optimization role](/optimization/cloud-provider-account) using a CloudFormation template deployed into your dedicated commitment account. If your organization requires that **all** infrastructure changes go through Terraform, you can create the equivalent IAM role directly — the role's trust policy, permissions, and function are identical to the CloudFormation version.

<Note>
  This page only covers the **Optimization role** (commitment purchasing). If you haven't already reviewed how commitment purchasing works and the dedicated commitment account model, start with [Commitment Purchasing Authorization](/optimization/cloud-provider-account) first.
</Note>

***

## What this role does

The Optimization role is assumed by Cloud Capital's AWS account to purchase and manage Savings Plans and Reserved Instances **in your dedicated, empty commitment account only**. It has no read access to your cost data, no visibility into workload accounts, and cannot modify IAM policies or account settings. See [What Cloud Capital can and cannot do](/optimization/cloud-provider-account#what-cloud-capital-can-and-cannot-do) for the full breakdown.

***

## Required parameters

Your Terraform configuration needs the following three values:

| Parameter                       | Value                                         |
| ------------------------------- | --------------------------------------------- |
| `param_CrossAccountRoleName`    | `CloudCapitalOptimizationRole`                |
| `param_CloudCapitalAccountRole` | `708317008333`                                |
| `param_CloudCapitalExternalId`  | Your Cloud Capital Integration ID — see below |

<Note>
  Find your `CloudCapitalExternalId` in the Cloud Capital application at [app.cloudcapital.co/integrations](https://app.cloudcapital.co/integrations) — it's labeled **Integration ID** there. It's a UUID, e.g. `a1b2c3d4-e5f6-7890-abcd-ef1234567890`.
</Note>

***

## IAM policy JSON

The two policy documents below are extracted directly from Cloud Capital's Optimization CloudFormation template. Import or reference them as-is in your Terraform configuration — do not modify the actions, effects, or condition keys.

### Trust policy (assume role policy)

This policy allows only Cloud Capital's AWS account to assume the role, and only when the correct External ID is presented.

```json trust-policy.json theme={null}
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "AWS": "708317008333"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "StringEquals": {
          "sts:ExternalId": "<param_CloudCapitalExternalId>"
        }
      }
    }
  ]
}
```

Replace `<param_CloudCapitalExternalId>` with your Cloud Capital Integration ID from [app.cloudcapital.co/integrations](https://app.cloudcapital.co/integrations).

### Permissions policy

This policy scopes the role to purchasing and managing commitments only.

```json permissions-policy.json theme={null}
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:PurchaseReservedCapacityOfferings",
        "athena:CancelCapacityReservation",
        "athena:CreateCapacityReservation",
        "athena:DeleteCapacityReservation",
        "athena:PutCapacityAssignmentConfiguration",
        "athena:UpdateCapacityReservation",
        "bedrock:CreateProvisionedModelThroughput",
        "bedrock:DeleteProvisionedModelThroughput",
        "bedrock:UpdateProvisionedModelThroughput",
        "cloudfront:CreateSavingsPlan",
        "cloudfront:UpdateSavingsPlan",
        "memorydb:PurchaseReservedNodesOffering",
        "memorydb:TagResource",
        "ec2:AcceptReservedInstancesExchangeQuote",
        "ec2:CancelReservedInstancesListing",
        "ec2:CreateReservedInstancesListing",
        "ec2:DeleteQueuedReservedInstances",
        "ec2:Describe*",
        "ec2:GetCapacityReservationUsage",
        "ec2:GetReservedInstancesExchangeQuote",
        "ec2:ModifyReservedInstances",
        "ec2:PurchaseHostReservation",
        "ec2:PurchaseReservedInstancesOffering",
        "elasticache:PurchaseReservedCacheNodesOffering",
        "es:PurchaseReservedInstanceOffering",
        "medialive:PurchaseOffering",
        "rds:PurchaseReservedDbInstancesOffering",
        "redshift:AcceptReservedNodeExchange",
        "redshift:PurchaseReservedNodeOffering",
        "savingsplans:*",
        "servicequotas:*",
        "support:*"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "iam:CreateServiceLinkedRole"
      ],
      "Resource": "*"
    }
  ]
}
```

***

## Example Terraform configuration

The following wires the two policy documents above together with the required parameters using standard `aws_iam_role` and `aws_iam_role_policy` resources.

```hcl main.tf theme={null}
variable "cross_account_role_name" {
  description = "The name of the cross account role that Cloud Capital will assume"
  type        = string
  default     = "CloudCapitalOptimizationRole"
}

variable "cloud_capital_account_id" {
  description = "The Cloud Capital AWS account that will assume the role"
  type        = string
  default     = "708317008333"
}

variable "cloud_capital_external_id" {
  description = "The Integration ID from app.cloudcapital.co/integrations"
  type        = string
}

resource "aws_iam_role" "cloud_capital_optimization" {
  name = var.cross_account_role_name

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Sid    = ""
        Effect = "Allow"
        Principal = {
          AWS = var.cloud_capital_account_id
        }
        Action = "sts:AssumeRole"
        Condition = {
          StringEquals = {
            "sts:ExternalId" = var.cloud_capital_external_id
          }
        }
      }
    ]
  })
}

resource "aws_iam_role_policy" "cloud_capital_optimization_policy" {
  name = "CloudCapitalOptimizationPolicy"
  role = aws_iam_role.cloud_capital_optimization.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "dynamodb:PurchaseReservedCapacityOfferings",
          "athena:CancelCapacityReservation",
          "athena:CreateCapacityReservation",
          "athena:DeleteCapacityReservation",
          "athena:PutCapacityAssignmentConfiguration",
          "athena:UpdateCapacityReservation",
          "bedrock:CreateProvisionedModelThroughput",
          "bedrock:DeleteProvisionedModelThroughput",
          "bedrock:UpdateProvisionedModelThroughput",
          "cloudfront:CreateSavingsPlan",
          "cloudfront:UpdateSavingsPlan",
          "memorydb:PurchaseReservedNodesOffering",
          "memorydb:TagResource",
          "ec2:AcceptReservedInstancesExchangeQuote",
          "ec2:CancelReservedInstancesListing",
          "ec2:CreateReservedInstancesListing",
          "ec2:DeleteQueuedReservedInstances",
          "ec2:Describe*",
          "ec2:GetCapacityReservationUsage",
          "ec2:GetReservedInstancesExchangeQuote",
          "ec2:ModifyReservedInstances",
          "ec2:PurchaseHostReservation",
          "ec2:PurchaseReservedInstancesOffering",
          "elasticache:PurchaseReservedCacheNodesOffering",
          "es:PurchaseReservedInstanceOffering",
          "medialive:PurchaseOffering",
          "rds:PurchaseReservedDbInstancesOffering",
          "redshift:AcceptReservedNodeExchange",
          "redshift:PurchaseReservedNodeOffering",
          "savingsplans:*",
          "servicequotas:*",
          "support:*"
        ]
        Resource = "*"
      },
      {
        Effect   = "Allow"
        Action   = ["iam:CreateServiceLinkedRole"]
        Resource = "*"
      }
    ]
  })
}

output "cloud_capital_optimization_role_arn" {
  description = "Role ARN for Cloud Capital"
  value       = aws_iam_role.cloud_capital_optimization.arn
}
```

<Warning>
  Deploy this into the same **dedicated, empty commitment account** described in [Commitment Purchasing Authorization](/optimization/cloud-provider-account#setting-up-the-dedicated-commitment-account) — not your management/payer account and not an account running workloads.
</Warning>

***

## Setup

<Steps>
  <Step title="Create a dedicated commitment account">
    If you haven't already, create a new empty account in your AWS Organization to hold all commitments Cloud Capital purchases on your behalf. See [Creating an AWS account in your organization](https://docs.aws.amazon.com/accounts/latest/reference/manage-acct-creating.html).
  </Step>

  <Step title="Get your Cloud Capital External ID">
    Sign in to the Cloud Capital application and copy the **Integration ID** from [app.cloudcapital.co/integrations](https://app.cloudcapital.co/integrations). It's a UUID, e.g. `a1b2c3d4-e5f6-7890-abcd-ef1234567890`.
  </Step>

  <Step title="Apply the Terraform configuration">
    Add the configuration above to your Terraform codebase, set `cloud_capital_external_id` to the value from the previous step, and apply it in the dedicated commitment account.
  </Step>

  <Step title="Share the Role ARN with Cloud Capital">
    After apply completes, copy the `cloud_capital_optimization_role_arn` output and provide it to your Cloud Capital representative, or paste it into the Cloud Capital application as directed during onboarding. This completes the authorization.
  </Step>
</Steps>

<Info>
  All commitment customers must also have the Forecasting role deployed in their management/payer account to read cost and usage data. That role is separate from the Optimization role covered here — talk to your Cloud Capital representative if you need a Terraform-equivalent for Forecasting as well.
</Info>
