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

# Container Image Components

> Container image components allow you to use prebuilt container images.

Container images allow you to import prebuilt container images from public sources, private AWS ECR repositories, and private GCP Artifact Registry (GAR) repositories.

## Container Images vs Docker Build images

Container images are used to import *prebuilt* images, that have already been pushed to either a public registry, a private AWS ECR repository, or a private GCP Artifact Registry repository.

### When to use a docker build component

Use a docker build component if:

* your container build process does not do any additional scanning/processing on your built container images
* you do not need to access any internal resources during the build process
* you want to get started faster

### When to use a container image component

* you want to leverage public images
* you post process or scan built container images
* your build process accesses internal resources (such as a private dependency registry)
* you value building once, and using everywhere for consistency purposes

<Note>
  If you have private prebuilt images in a registry other than AWS ECR or GCP Artifact Registry, [please get in touch](https://nuon.co/contact-us)!
</Note>

## Configuring a container image component

### Using a Public Image

To use a public image from any container registry, configure the `public` block.

```toml components/public_image.toml theme={null}
# container-image
name   = "public"
type   = "container_image"

[public]
image_url = "kennethreitz/httpbin"
tag       = "latest"
```

### Using a Private AWS ECR Image

To use an image from a private ECR registry, configure the `aws_ecr` block.

```toml components/ecr_image.toml theme={null}
# container-image
name   = "ecr"
type   = "container_image"

[aws_ecr]
image_url    = "123927561584.dkr.ecr.us-west-2.amazonaws.com/repo-name"
tag          = "latest"
region       = "us-west-2"
iam_role_arn = "arn:aws:iam::123927561584:role/nuon-container-image-access"
```

To use an AWS ECR image, [follow the access setup directions](#granting-nuon-access-to-pull-images). Both Nuon-hosted (AWS) and self-hosted-on-GCP customers can pull from the same role.

### Using a Private GCP GAR Image

To use an image from a private Google Artifact Registry, configure the `gcp_gar` block.

```toml components/gar_image.toml theme={null}
# container-image
name   = "gar"
type   = "container_image"

[gcp_gar]
image_url      = "us-central1-docker.pkg.dev/my-project/my-repo/my-image"
tag            = "latest"
region         = "us-central1"
gcp_project_id = "my-project"

# Reader SA that Nuon impersonates to pull. Optional for self-hosted-on-GCP
# customers if the customer's ctl-api SA already has artifactregistry.reader
# directly on the repo; required for Nuon-hosted (AWS) customers.
service_account_email = "nuon-puller@my-project.iam.gserviceaccount.com"

# Required for Nuon-hosted (AWS) customers. Workload Identity Provider that
# Nuon's AWS ctl-api federates against before impersonating the reader SA.
workload_identity_provider = "projects/123456789/locations/global/workloadIdentityPools/nuon-aws/providers/aws-prod"
```

To use a GAR image, [follow the access setup directions](#gcp-gar-access). Both Nuon-hosted (AWS) and self-hosted-on-GCP customers can pull from the same GAR repository.

## Deployments

Container image components *cannot* be deployed directly in a customer install. When an image is released, it will be *synced*
into the customer install and made available to other components via [variables](/guides/using-variables).

To deploy a Container image component, reference the image from a Helm component or Terraform component:

```toml components/eks_deployment.toml theme={null}
# helm
name       = "eks_deployment"
type       = "helm_chart"
chart_name = "<your-app>"

[connected_repo]
repo      = "<your-app>"
directory = "components/helm-chart"
branch    = "main"

[values]
"env.IMAGE_TAG"        = "{{.nuon.components.app_image.image.tag}}"
"env.IMAGE_REPOSITORY" = "{{.nuon.components.app_image.image.repository.uri}}"
```

```toml components/ecs_service.toml theme={null}
# terraform
name              = "ecs_service"
type              = "terraform_module"
terraform_version = "v1.6.3"

[connected_repo]
repo      = "<your-app>"
directory = "components/ecs-service"
branch    = "main"

[vars]
"image_tag"        = "{{.nuon.components.app_image.image.tag}}"
"image_repository" = "{{.nuon.components.app_image.image.repository.uri}}"
```

```toml components/eks_job.toml theme={null}
# action
name      = "eks_job"
type      = "job"
image_url = "{{.nuon.components.app_image.image.repository.uri}}"
tag       = "{{.nuon.components.app_image.image.tag}}"
```

## Image Syncing

When a Container image component is released, Nuon will automatically sync the image into the end customer account. This
image is stored in a local registry that is provisioned in the customer account.

Nuon image syncing allows you to sync images into accounts, without worrying about cross account permissions, registry
authentication or publishing public images. Any `Dockerfile` in a repo can be built, and synced.

The sync process works by creating a 1-time authentication flow that grants the install runner access to pull the image
from the org data plane, and copy it into the local registry.

## Granting Nuon Access to Pull Images

Nuon-hosted runs in AWS, and we also offer a [self-hosted BYOC deployment on GCP](/guides/self-hosted/gcp). Pick the
section that matches your registry and the deployment kind your customers are using.

| Image registry        | Customer deployment | Setup                                                                                     |
| --------------------- | ------------------- | ----------------------------------------------------------------------------------------- |
| AWS ECR               | Nuon-hosted (AWS)   | [AWS ECR Access IAM Role](#aws-ecr-access-iam-role)                                       |
| AWS ECR               | Self-hosted on GCP  | [AWS ECR from a Self-Hosted-on-GCP Customer](#aws-ecr-from-a-self-hosted-on-gcp-customer) |
| GCP Artifact Registry | Nuon-hosted (AWS)   | [GAR for Nuon-hosted (AWS) customers](#gar-for-nuon-hosted-aws-customers)                 |
| GCP Artifact Registry | Self-hosted on GCP  | [GCP GAR Access](#gcp-gar-access)                                                         |

If you have customers on both deployments, you can set both inputs on the same role or service account. Both modules add the new principals alongside any existing ones.

### AWS ECR Access IAM Role

To use a private AWS ECR image, you must create an IAM role that grants Nuon access to pull your container image. When
building your component, `nuon` will automatically assume the role and pull the image from your build runner.

The easiest way to setup an IAM role to configure your component with is using our [Terraform Module](https://registry.terraform.io/modules/nuonco/ecr-access/aws).

```hcl theme={null}
module "nuon_ecr_access" {
  source  = "nuonco/ecr-access/aws"

  repository_arns = ["<repository-arn>"]
}

output "iam_role_arn" {
  value = module.nuon_ecr_access.iam_role_arn
}
```

<Note>
  If you are having trouble finding the repository ARN in the AWS console, you can run `aws ecr describe-repositories` to
  print the ARNs of all repositories in your current context.
</Note>

### AWS ECR from a Self-Hosted-on-GCP Customer

If your customer is running a self-hosted Nuon deployment on GCP, pass the customer's GCP service account unique IDs
via `gcp_principals` so they can assume the role via Workload Identity Federation. Two SAs need to be listed:

* The org runner SA, which pulls source for builds. Display name: `Nuon org runner <org_id>`.
* The ctl-api SA, which fetches image metadata for `external_image` components. Display name: `ctl-api for <install_id>`.

<Note>
  Requires `nuonco/ecr-access/aws` version `0.1.9` or later.
</Note>

```hcl theme={null}
module "nuon_ecr_access" {
  source  = "nuonco/ecr-access/aws"

  repository_arns = ["<repository-arn>"]

  gcp_principals = [
    {
      service_account_unique_id = "123456789012345678901"  # org runner SA UID
      service_account_email     = "<org-id-truncated>@<customer-project>.iam.gserviceaccount.com"
    },
    {
      service_account_unique_id = "987654321098765432109"  # ctl-api SA UID
      service_account_email     = "ctl-api-<install-id-truncated>@<customer-project>.iam.gserviceaccount.com"
    },
  ]
}
```

<Note>
  Don't construct the SA emails by hand. Nuon truncates the org and install IDs to fit GCP's 30-character SA name limit,
  and the truncation length varies. Look the SAs up directly in the customer's project. The full org and install IDs are
  preserved in each SA's display name.
</Note>

Look them up with:

```bash theme={null}
gcloud iam service-accounts list \
  --project=<customer-project> \
  --filter='displayName~"Nuon org runner" OR displayName~"ctl-api for"' \
  --format='table(email,uniqueId,displayName)'
```

<Note>
  The default Nuon-hosted (AWS) trust principal stays in place. Adding `gcp_principals` is additive, so the same role
  works for both Nuon-hosted and self-hosted-on-GCP customers.
</Note>

### GCP GAR Access

You grant access to a private GAR repository by creating a reader service account on the repo and allowing each
customer's identity to impersonate it. The same module covers both customer-deployment kinds. Use
`customer_principals` for self-hosted-on-GCP customers, `aws_principals` for Nuon-hosted (AWS) customers, or both.

The easiest way to set this up is using our [Terraform Module](https://registry.terraform.io/modules/nuonco/gar-access/google):

```hcl theme={null}
module "nuon_gar_access" {
  source  = "nuonco/gar-access/google"

  project_id          = "<your-gcp-project>"
  repository_location = "us-central1"
  repository_id       = "<repo-name>"

  customer_principals = [
    "serviceAccount:ctl-api-<install>@<customer-project>.iam.gserviceaccount.com",
  ]
}

output "gar_access_sa_email" {
  value = module.nuon_gar_access.service_account_email
}
```

Then set `service_account_email` in your component's `gcp_gar` block to the SA email the module emits.

#### GAR for Nuon-hosted (AWS) customers

If some of your customers pull from this GAR repo via Nuon-hosted ctl-api running on AWS, pass each customer's AWS
account ID via `aws_principals`. You can use it alongside `customer_principals` if you also have self-hosted-on-GCP
customers. The module sets up a Workload Identity Pool and AWS Provider per account, and lets the federated principal
impersonate the GAR-access SA.

```hcl theme={null}
module "nuon_gar_access" {
  source = "nuonco/gar-access/google"

  project_id          = "<your-gcp-project>"
  repository_location = "us-central1"
  repository_id       = "<repo-name>"

  aws_principals = [
    { aws_account_id = "123456789012" },
  ]
}

output "workload_identity_provider_paths" {
  value = module.nuon_gar_access.workload_identity_provider_paths
}
```

<Note>
  Requires `nuonco/gar-access/google` version `0.2.0` or later.
</Note>

In the customer's component config, set `gcp_gar.service_account_email` to the GAR-access SA email, and set
`gcp_gar.workload_identity_provider` to the provider path for that customer's AWS account from the module's
`workload_identity_provider_paths` output.

See the full set of `gcp_gar` fields in the [container-image config reference](/config-ref/container-image#gcp_gar).

## Importing Images Outside of Supported Registries

We currently support public container images, private AWS ECR repositories, and private GCP Artifact Registry repositories.

If your registry is supported by AWS ECR's [pull through
cache](https://docs.aws.amazon.com/AmazonECR/latest/userguide/pull-through-cache-working.html), the easiest way to
import the images into Nuon is to setup a pull through cache and configure your container image to use it.

This works for [Docker Hub](https://hub.docker.com/), [Github Container Registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry) and [Microsoft Azure Container Registry](https://azure.microsoft.com/en-us/products/container-registry).

<Note>
  If you would like to use a different private container registry, we would love to know more. Please [get in touch](https://nuon.co/contact-us) to tell us more about your use case.
</Note>
