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

# Docker

> Create a Docker secret to store container registry credentials for pulling images from private registries like Docker Hub, GHCR, or ACR.

Docker secrets store container registry credentials, enabling your workloads to pull images from private registries like Docker Hub, GitHub Container Registry, Azure Container Registry, or any Docker-compatible registry.

## Use Cases

* **Private Docker Hub**: Pull images from private Docker Hub repositories
* **GitHub Container Registry**: Access private packages hosted on GHCR
* **Azure Container Registry**: Pull images from ACR
* **Google Artifact Registry**: Access private Google container images
* **Self-Hosted Registries**: Connect to private/enterprise registries
* **Cross-Org Images**: Pull images from another Control Plane org

<Note>
  Images stored in your current Control Plane org don't require a pull secret. Reference them directly using the `//image/IMAGE:TAG` format.
</Note>

## Configuration Options

The Docker secret uses the standard Docker config.json format:

```json theme={null}
{
  "auths": {
    "<registry-url>": {
      "username": "<username>",
      "password": "<password-or-token>"
    }
  }
}
```

You can include credentials for multiple registries in a single secret.

***

## Create a Docker Secret

<Tabs>
  <Tab title="Console UI">
    <Steps>
      <Step title="Navigate to Secrets">
        In the Console, navigate to **Secrets** and click **New**, or use the **Create** dropdown in the top-right corner and select **Secret**.
      </Step>

      <Step title="Enter basic information">
        Enter a **Name** and optional **Description**.
      </Step>

      <Step title="Select secret type">
        Select **Docker** as the secret type.
      </Step>

      <Step title="Configure credentials">
        Click **Data** in the left pane. Enter the **Docker Secret Data** (JSON format), or drag and drop a file / click to import.
      </Step>

      <Step title="Create the secret">
        Click **Create**.
      </Step>
    </Steps>
  </Tab>

  <Tab title="CLI">
    **Option 1:** Use your existing Docker config file:

    ```bash theme={null}
    cpln secret create-docker \
      --name dockerhub-credentials \
      --file ~/.docker/config.json \
      --org my-org
    ```

    **Option 2:** Create a dedicated config file:

    ```json title="docker-config.json" theme={null}
    {
      "auths": {
        "https://index.docker.io/v1/": {
          "username": "my-username",
          "password": "my-access-token"
        }
      }
    }
    ```

    ```bash theme={null}
    cpln secret create-docker \
      --name dockerhub-credentials \
      --file docker-config.json \
      --org my-org
    ```

    <Tip>
      For Docker Hub, use a [Personal Access Token](https://hub.docker.com/settings/security) instead of your password for better security and easier revocation.
    </Tip>
  </Tab>

  <Tab title="Terraform">
    Docker Hub example:

    ```hcl theme={null}
    resource "cpln_secret" "dockerhub" {
      name        = "dockerhub-credentials"
      description = "Docker Hub private registry access"

      docker = jsonencode({
        auths = {
          "https://index.docker.io/v1/" = {
            username = "my-username"
            password = "my-access-token"
          }
        }
      })
    }
    ```

    GitHub Container Registry example:

    ```hcl theme={null}
    resource "cpln_secret" "ghcr" {
      name        = "ghcr-credentials"
      description = "GitHub Container Registry access"

      docker = jsonencode({
        auths = {
          "ghcr.io" = {
            username = "my-github-username"
            password = "ghp_xxxxxxxxxxxx"  # PAT with read:packages scope
          }
        }
      })
    }
    ```

    Multiple registries in one secret:

    ```hcl theme={null}
    resource "cpln_secret" "multi_registry" {
      name        = "multi-registry-credentials"
      description = "Access to multiple container registries"

      docker = jsonencode({
        auths = {
          "https://index.docker.io/v1/" = {
            username = "my-username"
            password = "my-access-token"
          }
          "ghcr.io" = {
            username = "my-github-username"
            password = "ghp_xxxxxxxxxxxx"
          }
        }
      })
    }
    ```
  </Tab>

  <Tab title="Pulumi">
    <Tabs>
      <Tab title="TypeScript">
        ```typescript theme={null}
        import * as cpln from "@pulumiverse/cpln";

        const dockerSecret = new cpln.Secret("dockerhub-credentials", {
          name: "dockerhub-credentials",
          description: "Docker Hub private registry access",
          docker: JSON.stringify({
            auths: {
              "https://index.docker.io/v1/": {
                username: "my-username",
                password: "my-access-token",
              },
            },
          }),
        });
        ```
      </Tab>

      <Tab title="Python">
        ```python theme={null}
        import json
        import pulumiverse_cpln as cpln

        docker_secret = cpln.Secret("dockerhub-credentials",
            name="dockerhub-credentials",
            description="Docker Hub private registry access",
            docker=json.dumps({
                "auths": {
                    "https://index.docker.io/v1/": {
                        "username": "my-username",
                        "password": "my-access-token",
                    }
                }
            }))
        ```
      </Tab>

      <Tab title="Go">
        ```go theme={null}
        package main

        import (
            "encoding/json"
            "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
            "github.com/pulumiverse/pulumi-cpln/sdk/go/cpln"
        )

        func main() {
            pulumi.Run(func(ctx *pulumi.Context) error {
                dockerConfig, _ := json.Marshal(map[string]interface{}{
                    "auths": map[string]interface{}{
                        "https://index.docker.io/v1/": map[string]string{
                            "username": "my-username",
                            "password": "my-access-token",
                        },
                    },
                })

                _, err := cpln.NewSecret(ctx, "dockerhub-credentials", &cpln.SecretArgs{
                    Name:        pulumi.String("dockerhub-credentials"),
                    Description: pulumi.String("Docker Hub private registry access"),
                    Docker:      pulumi.String(string(dockerConfig)),
                })
                return err
            })
        }
        ```
      </Tab>

      <Tab title="C#">
        ```csharp theme={null}
        using System.Collections.Generic;
        using System.Text.Json;
        using Pulumi;
        using Pulumiverse.Cpln;
        using Pulumiverse.Cpln.Inputs;

        return await Deployment.RunAsync(() =>
        {
            var dockerConfig = JsonSerializer.Serialize(new
            {
                auths = new Dictionary<string, object>
                {
                    ["https://index.docker.io/v1/"] = new
                    {
                        username = "my-username",
                        password = "my-access-token",
                    }
                }
            });

            var dockerSecret = new Secret("dockerhub-credentials", new SecretArgs
            {
                Name = "dockerhub-credentials",
                Description = "Docker Hub private registry access",
                Docker = dockerConfig,
            });
        });
        ```
      </Tab>
    </Tabs>
  </Tab>
</Tabs>

***

## Common Registry URLs

| Registry                  | URL                                         | Notes                           |
| :------------------------ | :------------------------------------------ | :------------------------------ |
| Docker Hub                | `https://index.docker.io/v1/`               | Use access token, not password  |
| GitHub Container Registry | `ghcr.io`                                   | PAT with `read:packages` scope  |
| Azure Container Registry  | `<registry>.azurecr.io`                     | Service principal or admin user |
| Google Artifact Registry  | `<region>-docker.pkg.dev`                   | Service account JSON key        |
| AWS ECR                   | Use [ECR secret](/guides/create-secret/ecr) | Dedicated secret type available |
| Control Plane (other org) | `<org>.registry.cpln.io`                    | Service account token           |

***

## Using the Secret

After creating the Docker secret, add it as a **pull secret** to your GVC:

<Tabs>
  <Tab title="Console UI">
    <Steps>
      <Step title="Navigate to your GVC">
        Open your GVC in the Console.
      </Step>

      <Step title="Open Pull Secrets">
        Click **Pull Secrets** in the left pane.
      </Step>

      <Step title="Add the secret">
        Click **Add** and select your Docker secret.
      </Step>

      <Step title="Save changes">
        Click **Save**.
      </Step>
    </Steps>
  </Tab>

  <Tab title="CLI">
    ```bash theme={null}
    cpln gvc update my-gvc \
      --set spec.pullSecretLinks+="dockerhub-credentials" \
      --org my-org
    ```
  </Tab>

  <Tab title="Terraform">
    ```hcl theme={null}
    resource "cpln_gvc" "my_gvc" {
      name = "my-gvc"

      pull_secrets = [
        cpln_secret.dockerhub.name
      ]
    }
    ```
  </Tab>

  <Tab title="Pulumi">
    <Tabs>
      <Tab title="TypeScript">
        ```typescript theme={null}
        import * as cpln from "@pulumiverse/cpln";

        const gvc = new cpln.Gvc("my-gvc", {
          name: "my-gvc",
          pullSecrets: [dockerSecret.name],
        });
        ```
      </Tab>

      <Tab title="Python">
        ```python theme={null}
        import pulumiverse_cpln as cpln

        gvc = cpln.Gvc("my-gvc",
            name="my-gvc",
            pull_secrets=[docker_secret.name])
        ```
      </Tab>

      <Tab title="Go">
        ```go theme={null}
        gvc, err := cpln.NewGvc(ctx, "my-gvc", &cpln.GvcArgs{
            Name:        pulumi.String("my-gvc"),
            PullSecrets: pulumi.StringArray{dockerSecret.Name},
        })
        ```
      </Tab>

      <Tab title="C#">
        ```csharp theme={null}
        var gvc = new Gvc("my-gvc", new GvcArgs
        {
            Name = "my-gvc",
            PullSecrets = new[] { dockerSecret.Name },
        });
        ```
      </Tab>
    </Tabs>
  </Tab>
</Tabs>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="GVC Pull Secrets" icon="key" href="/reference/gvc#pull-secrets">
    Configure pull secrets at the GVC level
  </Card>

  <Card title="ECR Secrets" icon="aws" href="/guides/create-secret/ecr">
    Use the dedicated ECR secret type for AWS
  </Card>
</CardGroup>
