> For the complete documentation index, see [llms.txt](https://developer.harness.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.harness.io/cloud-cost-management/3.0/knowledge-base-and-reference-architecture/patterns/ccm-connectors-via-code-repo-and-iacm.md).

# Harness Modules Code Repo & IaCM for Automatic Creation of CCM Cloud Connectors

Use Harness Modules Code Repository and Infrastructure as Code (IaCM) to create Cloud & AI Cost Management (CACM) cloud connectors at scale. This example focuses on AWS CACM cloud connectors, but the process also applies to other cloud providers.

Store your Terraform code in Code Repository. Then use the repository in the IaCM module to apply the connectors.

Before you begin, understand Harness Modules Code Repository, IaCM, and CACM.

### Set up <a href="#setup" id="setup"></a>

For the pipeline, use a Kubernetes cluster with a delegate. The delegate needs permission to deploy a pod.

#### Create a project <a href="#create-a-project" id="create-a-project"></a>

The project will use the Code Repository and IaCM modules.

![Code Repository and IaCM modules in a Harness project](/files/Pndscmy34XWcKYF8ClF4)

#### Create a Code Repository and add IaC code for connectors <a href="#create-a-new-code-repository-and-add-iac-code-for-connectors" id="create-a-new-code-repository-and-add-iac-code-for-connectors"></a>

This will be used to store and maintain our IaC.

1. Navigate to your new project, then create a Code Repository. This repository holds the code for your CACM connectors.

![Create a Code Repository in a Harness project](/files/w6P3hnjy5kFaUVjuWEzW)

2. Create a `main.tf` file with Terraform code. Use [Part 1](/cloud-cost-management/references/best-practices/aws/aws-connectors-and-roles.md#setup-providers) for providers. Use [Part 2](/cloud-cost-management/references/best-practices/aws/aws-connectors-and-roles.md#use-the-built-in-locals-value-to-define-the-accounts-statically) to define accounts statically.

For `role_arn`, replace `HarnessCERole` with the role name provisioned in each AWS account. The role needs the required permissions for each CCM feature. Go to [Create roles in each AWS account](/cloud-cost-management/references/best-practices/aws/aws-connectors-and-roles.md#create-roles-in-each-aws-account) to configure roles.

```terraform
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
    harness = {
      source = "harness/harness"
    }
  }
}

provider "aws" {
  region = "us-east-1"
}

provider "harness" {}

data "harness_platform_current_account" "current" {}

locals {
  aws-non-prod = ["000000000005", "000000000006"]
  aws-prod = ["000000000007", "000000000008"]
}

resource "harness_platform_connector_awscc" "data" {
  for_each = toset(concat(local.aws-non-prod, local.aws-prod))

  identifier = "aws${each.key}"
  name       = "aws${each.key}"

  account_id = trimspace(each.key)

  features_enabled = [
    "OPTIMIZATION",
    "VISIBILITY",
    "GOVERNANCE",
  ]
  cross_account_access {
    role_arn    = "arn:aws:iam::${each.key}:role/HarnessCERole"
    external_id = "harness:891928451355:${data.harness_platform_current_account.current.id}"
  }
}
```

#### Create an IaCM workspace <a href="#create-a-new-iacm-workspace" id="create-a-new-iacm-workspace"></a>

Use this workspace to store IaC configuration, variables, states, and resources for AWS CACM cloud connectors.

1. Navigate to the IaCM module and create a new workspace.
   * Provisioner:
     * Connector (a few options):
       * If you have a AWS connector for your master billing account already (not a CACM AWS connector), choose this for your connector.
       * If you need to create a new connector, the suggestion is to [use OIDC](/harness-ai/use-harness-platform/connectors/cloud-providers/ref-cloud-providers/aws-connector-settings-reference.md#credentials). You'll have to provision a role in your master billing AWS account that trusts Harness. In setup, you can skip setting up the backoff strategy and select connect through Harness platform for the connectivity mode. You have to select a connector to complete setup. Even though we aren't going to use this connector in our example (because we are getting the account ids statically in the Terraform code), we still have to specify the connector.
     * Workspace Type:
       * Choose the latest version of OpenTofu as our support for Terraform ends with 1.5.7 [due to licensing changes](/infrastructure-as-code-management/troubleshooting-and-resources/whats-supported.md#supported-iac-frameworks).
   * Repository:
     * Choose Harness Code Repository and select the repository we created in the first step. Select main as the branch and the folder path should be blank as we created the main.tf in the root directory.

![IaCM workspace configuration in Harness](/files/cEAuhJEwxXvgw1NTthqz)

**Define variables**

The AWS authentication is handled via the OIDC connector defined above, but Harness authentication still needs to be configured. To define the Harness authentication, we need to define two environment variables: Harness account id and Harness platform API key.

To create the Harness platform API key:

1. Create a service account
2. Give the service account account admin for all account level resources. This is overpermissive. If you want, you can also create a custom role that only has connector admin.
3. Create an API key, then a token. Copy the token value
4. Create a new secret with the token

![Create a Harness service account](/files/fhnvKUcKdFCIWc26tiIT)

![Create a token for the Harness service account](/files/JLaNRjRzXuWgBgfACGQm)

````
  ```
  HARNESS_ACCOUNT_ID (string). Built in Harness variable = <+account.identifier>
  HARNESS_PLATFORM_API_KEY (secret) = New secret created from the steps above
  ```
````

![Add Harness authentication variables to the IaCM workspace](/files/CsFDdZBuXwhnszCYmVuc)

#### Create a Terraform pipeline <a href="#create-a-terraform-pipeline" id="create-a-terraform-pipeline"></a>

Create a new pipeline. The pipeline will be used to run our init, plan, and apply Terraform stages.

1. Add a new stage. Select `Infrastructure` as the stage type and name the stage `ccm_connectors`
   * Select the infrastructure as Kubernetes, select the Kubernetes cluster you identified earlier on at the beginning of the setup portion of this guide, and choose your namespace

![Configure an Infrastructure stage in a Harness pipeline](/files/2OF87NBhk9wSX5304v2l)

2. Select the workspace we created in the step above
3. For execution, choose the 'Blank Canvas' operation
4. Add a step, select 'IACM OpenTofu Plugin'. Set the command to `init` and leave everything else the same
5. Add another step, select 'IACM OpenTofu Plugin'. Set the command to `plan` and leave everything else the same
6. Add another step, select 'IACM Approval'. Leave everything else the same
7. Add a final step, select 'IACM OpenTofu Plugin'. Set the command to `apply` and leave everything else the same
8. Save the stage

Things to consider:

1. By running this pipeline in your cluster, you are going to be pulling images into your cluster. If your company doesn't allow this, you'll either have to:
   * Get a security exception to be able to pull from Docker Hub or
   * Mirror the Harness image into your local repository, edit the step yamls of each step to update the step specs. You'll have to define the image and connector. If you don't have it already, you'll have to create a Docker connector for your company repo and specify

![Configure an OpenTofu step in a Harness pipeline](/files/DMsez0HEUIx7IEB9nEpp)

2. You'll need firewall exceptions for the steps as well. Each step must download OpenTofu at runtime. This was a conscious decision because you might have hundreds of workspaces using various OpenTofu versions, and managing all those versions would be a significant task.

### Run the pipeline <a href="#run-the-pipeline" id="run-the-pipeline"></a>

In the previous steps, we spent time going over setting up the OIDC connector to be able to read from the master billing account. This is necessary when you [want to provision a connector for each account in the organization dynamically](/cloud-cost-management/references/best-practices/aws/aws-connectors-and-roles.md#use-the-aws-provider-to-get-all-accounts-in-the-organization). In our example we don't actually need this because if you remember our IaC code, we are defining the account ids in code statically.

1. Run the pipeline. The code will run up until the approval step

![Pipeline execution waiting for approval](/files/BNJKNP5quoqLj045M9JH)

2. Review and approve the pipeline. In this example, I've been assigned Project Admin for all resources so I can approve the pipeline. If you want to add RBAC for who can approve your pipeline, either give them Project Admin or use the fine-grain `Approve` permission in the Infrastructure as Code section and create a custom role.

![Approve a Harness pipeline execution](/files/xkMR1CSneVe7S5NC9Mcd)

3. After the pipeline is complete, navigate to connectors in account setting and verify the connectors created. In the screenshot below, the status is failed only because the IAM role I'm expecting isn't in the accounts yet.

![Connector status after a pipeline execution](/files/nQ0q8MDAJVDUiE3dMHyG)

### Schedule pipeline runs <a href="#schedule-pipeline-runs" id="schedule-pipeline-runs"></a>

You can add a Cron trigger to run the pipeline on a frequency. This is useful for when new AWS accounts get added, we can automatically run the pipeline and pick create new connectors for them.

1. Select your pipeline, select 'Triggers' on the top right of the screen, and create a new trigger.
2. Scroll to the bottom of the trigger options and select 'Cron'
3. Run it daily (or whatever you prefer)

![Create a Cron trigger for a Harness pipeline](/files/yHBpK05ISKt6tLeq5skY)
