Addressing review comments

Signed-off-by: AbstractionFactory <179820029+abstractionfactory@users.noreply.github.com>
Co-authored-by: Martin Atkins <mart@degeneration.co.uk>
This commit is contained in:
AbstractionFactory 2025-02-04 15:52:26 +01:00 committed by Martin Atkins
parent eee2325e52
commit 26534ed2b5
5 changed files with 240 additions and 41 deletions

View File

@ -15,6 +15,9 @@ It's worth noting that many registry implementations, regarding ghcr.io, don't f
> [!TIP]
> There is some flexibility in how the data is stored, which also gave rise to [ORAS](https://oras.land/) (OCI Registry as Storage). For details, see the [ORAS section below](#oras).
> [!WARNING]
> The examples in this document are meant to showcase the protocol only, they are not indicative of how OpenTofu stores data in OCI!
## Authentication
Although registries don't necessarily need authentication, many public registries, such as `ghcr.io` and the Docker Hub require an anonymous token even to access public images. When accessing an endpoint, a client may receive a `WWW-Authenticate` header, indicating that authentication must be performed.
@ -45,13 +48,62 @@ The username/password part is optional for public registries and the response wi
### Index vs. image manifest
Manifests can have two types. An index (media type of `application/vnd.oci.image.index.v1+json` or `application/vnd.docker.distribution.manifest.list.v2+json`) contains a list of image manifests. This is useful when you want to distribute your image for multiple architectures (so-called multi-arch images).
Manifests can have two types. An index (media type of `application/vnd.oci.image.index.v1+json` or `application/vnd.docker.distribution.manifest.list.v2+json`) contains a list of image manifests. This is useful when you want to distribute your image for multiple architectures (so-called multi-platform images).
> [!TIP]
> Try it yourself: authenticate with a token as described above, then use the following command:
> ```
> curl -H "Authorization: Bearer djE6b3Blb..." https://ghcr.io/v2/opentofu/opentofu/manifests/1.8.0
> ```
>
> <details><summary>Result</summary>
>
> ```json
> {
> "schemaVersion": 2,
> "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
> "manifests": [
> {
> "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
> "size": 951,
> "digest": "sha256:105eb6b43b0704093cd48644437934d3eb9200c297756fe4e4d5ed2fccada56c",
> "platform": {
> "architecture": "386",
> "os": "linux"
> }
> },
> {
> "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
> "size": 951,
> "digest": "sha256:26b1e5ed87f80d3b2bb36769d90a448246bd1aa786f57bdc0b8907dc3d2b327f",
> "platform": {
> "architecture": "amd64",
> "os": "linux"
> }
> },
> {
> "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
> "size": 951,
> "digest": "sha256:4ac194402663bf948d022a9b3f79641565fc90cdae476829638f2dfcd4583c77",
> "platform": {
> "architecture": "arm64",
> "os": "linux"
> }
> },
> {
> "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
> "size": 951,
> "digest": "sha256:4ac9d6209f34675c869a63e41110b596e20a679a3c8451c9bd059bbb5a1ba564",
> "platform": {
> "architecture": "arm",
> "os": "linux",
> "variant": "v7"
> }
> }
> ]
> }
> ```
> </details>
Image manifests (media type of `application/vnd.oci.image.manifest.v1+json` or `application/vnd.docker.distribution.manifest.v2+json`) contain a list layers, each one referencing a blob. These layers are `.tar.gz` files containing the files in the image. The additional metadata is accessible through a separate blob referenced in the `config` section of the manifest.
@ -60,6 +112,39 @@ Image manifests (media type of `application/vnd.oci.image.manifest.v1+json` or `
> ```
> curl -H "Authorization: Bearer djE6b3Blb..." https://ghcr.io/v2/opentofu/opentofu/manifests/1.8.0-amd64
> ```
>
> <details><summary>Result</summary>
>
> ```json
> {
> "schemaVersion": 2,
> "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
> "config": {
> "mediaType": "application/vnd.docker.container.image.v1+json",
> "size": 2061,
> "digest": "sha256:f160637911afad6485d75b398c7c62b032f5040e641aff097e3035bcacf697de"
> },
> "layers": [
> {
> "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
> "size": 3415640,
> "digest": "sha256:930bdd4d222e2e63c22bd9e88d29b3c5ddd3d8a9d8fb93cf8324f4e7b9577cfb"
> },
> {
> "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
> "size": 8158438,
> "digest": "sha256:27a55bad853afb2cf5f203297db2e5f132a1f9afffce02a20e59284fed62ab4a"
> },
> {
> "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
> "size": 25145807,
> "digest": "sha256:22b79cf4f0efedf6423a10f5200cde934aaa8d6c7ece5a45939e87bb5af12e22"
> }
> ]
> }
> ```
>
> </details>
## API calls in the "Pull" category
@ -69,10 +154,33 @@ The distribution specification outlines that registries must implement all endpo
- The blob endpoint is located at `/v2/<name>/blobs/<digest>`, containing binary objects based on their digest (checksum). Note that this endpoint may return an HTTP redirect.
> [!TIP]
> Try it yourself: authenticate with a token as described above, then use the following command:
> Try it yourself: authenticate with a token as described above, then pull a blob from the manifest in the previous example. Observe the `location` header returned in the response, pointing to the actual download location of the blob.
> ```
> curl -H "Authorization: Bearer djE6b3Blb..." https://ghcr.io/v2/opentofu/opentofu/manifests/1.8.0
> curl -v -H "Authorization: Bearer djE6b3Blb..." https://ghcr.io/v2/opentofu/opentofu/blobs/sha256:22b79cf4f0efedf6423a10f5200cde934aaa8d6c7ece5a45939e87bb5af12e22
> ```
>
> <details><summary>Result</summary>
>
> ```
> > GET /v2/opentofu/opentofu/blobs/sha256:22b79cf4f0efedf6423a10f5200cde934aaa8d6c7ece5a45939e87bb5af12e22 HTTP/2
> > Host: ghcr.io
> > User-Agent: curl/8.5.0
> > Accept: */*
> > Authorization: Bearer djE...
> >
>
> < HTTP/2 307
> < content-length: 0
> < content-type: application/octet-stream
> < docker-distribution-api-version: registry/2.0
> < location: https://pkg-containers.githubusercontent.com/ghcr1/blobs/sha256:22b79cf4f0efedf6423a10f5200cde934aaa8d6c7ece5a45939e87bb5af12e22?se=2025-02-04T09%3A50%3A00Z&sig=FGZhe9e3oOMEbhebzW49Stfj9J1Cuy77Go77Ob7w8ro%3D&sp=r&spr=https&sr=b&sv=2019-12-12
> < date: Tue, 04 Feb 2025 09:40:56 GMT
> < x-github-request-id: D334:1069C0:704BB:71F3D:67A1E0A8
> <
> ```
> Note: We omitted the TLS output from this example for readability.
>
> </details>
> [!NOTE]
> The `<name>` part may contain additional `/` characters and must match the regular expression of `[a-z0-9]+((\.|_|__|-+)[a-z0-9]+)*(\/[a-z0-9]+((\.|_|__|-+)[a-z0-9]+)*)*`. This means that a name can consist of an arbitrary amount of path parts, up to the length limit of 255 characters for hostname + name. It is worth noting that many registry implementations place additional restrictions on the name, such as needing to include a project ID, group, namespace, etc. and they may disallow additional path parts beyond that. Therefore, we will have to map the provider addresses to the name in a flexible fashion, configurable for the user.
@ -83,6 +191,22 @@ The distribution specification outlines that registries must implement all endpo
> [!NOTE]
> An OCI `<digest>` can take the form of `scheme:value` and use any checksum algorithm. However, the specification states that `sha256` and `sha512` are standardized and compliant registries should support `sha256`.
## API calls in the "Push" category
These API calls are similar to the pull category above, but as the name suggest, are intended for publishing manifests and blobs.
You can do an upload in two ways:
1. First `POST` to the `/v2/<name>/blobs/uploads` endpoint, then `PUT` the blob contents to the URL indicated in the `Location` header from the first response.
2. Immediately `POST` the blob contents to `/v2/<name>/blobs/uploads/?digest=<digest>` indicating a pre-computed digest.
> [!TIP]
> The benefit of the first method is the ability to perform an upload in chunks using `PATCH` requests. See [the specification for details](https://github.com/opencontainers/distribution-spec/blob/main/spec.md#pushing-a-blob-in-chunks).
Once the blobs have been uploaded, you can push the manifest that references them. You can push a manifest by sending a `PUT` request to `/v2/<name>/manifests/<reference>`, where the reference should be the tag name the manifest should appear under.
It is worth noting that manifests can reference other manifests in their `subject` field. You can use this, for example, to sign a manifest and attach the signature to the manifest it signed. You can then use the referrers API described in the next section to query it.
## API calls in the "Content discovery" category
In addition to the "pull" category outlined above, registries may (but do not necessarily have to) implement the API endpoints in the "Content discovery" category. This category is useful when listing provider versions and consists of two endpoints:
@ -90,11 +214,64 @@ In addition to the "pull" category outlined above, registries may (but do not ne
- The tag listing endpoint is located at `/v2/<name>/tags/list` and supports additional filtering and pagination parameters. It lists all the tags (a kind of reference) that have manifests.
- The referrer listing endpoint is located at `/v2/<name>/referrers/<digest>` and returns the list of manifests that refer to a specific blob.
> [!WARNING]
> The tag listing endpoint is typically paginated. Client implementations must follow the `Link` header in the response to receive the entire list of tags.
> [!TIP]
> Try it yourself: authenticate with a token as described above, then use the following command:
> ```
> curl -H "Authorization: Bearer djE6b3Blb..." https://ghcr.io/v2/opentofu/opentofu/tags/list
> curl -v -H "Authorization: Bearer djE6b3Blb..." https://ghcr.io/v2/opentofu/opentofu/tags/list
> ```
>
> <details><summary>Results</summary>
>
> ```
> > GET /v2/opentofu/opentofu/tags/list HTTP/2
> > Host: ghcr.io
> > User-Agent: curl/8.5.0
> > Accept: */*
> > Authorization: Bearer djE6b3B...
> >
>
> < HTTP/2 200
> < content-type: application/json
> < docker-distribution-api-version: registry/2.0
> < link: </v2/opentofu/opentofu/tags/list?last=1.6.0-beta5-386&n=0>; rel="next"
> < date: Tue, 04 Feb 2025 09:47:19 GMT
> < x-github-request-id: D388:2C9949:B77F2:B977F:67A1E226
> <
> ```
> ```json
> {
> "name": "opentofu/opentofu",
> "tags": [
> "1.6.0-alpha1-arm64",
> "1.6.0-alpha1-amd64",
> "1.6.0-alpha1-arm",
> "1.6.0-alpha1-386",
> "1.6.0-alpha1",
> "1.6",
> "1",
> "latest",
> "sha256-722da07b0cdf5b6bdf12aff9339f7c274f70552144a0a28c0d2b970c083ffa5c.sig",
> "sha256-9b9662dbe859f81779d04ba0f8d2b415b09961d5e5435a25e2ba4566873058f0.sig",
> "sha256-d1aa9cfa30744d52a486b1dd58b7a65dd9d1ae9b79fc9b6ee5d0528ef9cfd54c.sig",
> "sha256-cd67ab05739a47503450c8d2da4abf89d5418f800d093f43a996de64a0d2fc33.sig",
> "sha256-28f8c87d6583f570acf7dd33afa6b17888e7f15ae595d74e16cbd4c82921f0d0.sig",
> "..."
> ]
> }
> ```
> Note: We omitted the TLS output from this example for readability.
>
> </details>
This category also includes a way to create references between distinct manifests. As an example, you can attach a digital signature of a manifest to an existing manifest by publishing the signature under a separate manifest, but referring to the manifest it signs. You can do this by pushing the new manifest with a `subject` field that references the original manifest.
Clients can query the `/v2/<name>/referrers/<reference>` endpoint to receive a list of manifests that refer to the current manifest in their `subject` field.
> [!TIP]
> The referrers API has been added in the Distribution spec version 1.1. Prominently, Cosign does not appear to use this API to attach signatures. Instead, Cosign creates a tag named after the checksum of the main manifest and suffix it with `.sig`.
## The `_catalog` extension
@ -139,7 +316,7 @@ ORAS uses a different media type to store the artifact in a layer:
> oras push \
> --artifact-type application/vnd.opentofu.provider \
> localhost:5000/oras:latest \
> terraform-provider-aws_5.84.0_linux_amd64.zip:archive/zip+opentofu-provider
> terraform-provider-aws_5.84.0_linux_amd64.zip:archive/zip
> ```
> You can now list the manifest:
> ```
@ -202,7 +379,7 @@ ORAS can also customize the config manifest using the `--config` option. This wi
It is worth noting that trying to pull an ORAS image with traditional containerization software will result in unexpected errors [as documented here](https://oras.land/docs/how_to_guides/manifest_config#docker-behaviors).
> [!NOTE]
> At the time of writing, [ORAS does not support multi-arch images](https://github.com/oras-project/oras/issues/1053).
> At the time of writing, [ORAS does not support multi-platform images](https://github.com/oras-project/oras/issues/1053).
---

View File

@ -46,10 +46,10 @@ However, there are several key reasons for deciding against this layout:
1. **It breaks provider checksums**<br />OpenTofu today records the checksums of all providers it sees in the `.terraform.lock.hcl` file. These checksums can have two formats: the `h1` (Go-specific directory hash) and the `zh` (ZIP hash) format. While the former would be suitable for hashing container images, hashes today are almost universally the of the latter format. Computing a SHA256 hash over a ZIP file is much simpler than extracting its contents and using a [Go-specific hashing format over the files](https://pkg.go.dev/golang.org/x/mod/sumdb/dirhash). Provider authors publish their checksums in the SHA256SUMS file when releasing providers and sign the checksums file with their GPG key. Fortunately for us, OCI registries also use SHA256 checksums as blob identifiers, so storing the ZIP file in a blob in OCI will guarantee that the checksum doesn't change even when switching from the OpenTofu Registry to a mirrored OCI registry. In contrast, a container image-like layout would mean you have to run `tofu providers lock` to update the checksums in your `.terraform.lock.hcl` and your lock file would now be exclusive to your OCI mirror.
2. **Supporting layers adds complexity**<br />OpenTofu today contains over 300.000 lines of code. Supporting the diff-tar layer format adds complexity to the codebase and increases the resource consumption of the download. Simply downloading a ZIP-blob allows us to reuse much of the code already in place in OpenTofu today.
Therefore, we have decided to use a layout that does not indicate a container image and follows the [ORAS](https://oras.land) conventions with added multi-arch support. See the [Providers](5-providers.md) and [Modules](6-modules.md) documents for details on the respective artifact layouts.
Therefore, we have decided to use a layout that does not indicate a container image and follows the [ORAS](https://oras.land) conventions with added multi-platform support. See the [Providers](5-providers.md) and [Modules](6-modules.md) documents for details on the respective artifact layouts.
> [!NOTE]
> In contrast to providers, modules currently have a protocol option. This allows us to integrate them safely without breaking existing tooling. However, to indicate possible OCI layout changes in the future, we will use the protocol prefix of `oci+zip://`.
> In contrast to providers, modules currently have a protocol option. This allows us to integrate them safely without breaking existing tooling. However, to indicate possible OCI layout changes in the future, we will use the protocol prefix of `oci://`.
## Software Bill of Materials (SBOM)
@ -74,7 +74,7 @@ For both purposes, OpenTofu will consider SBOM-specific file names in the provid
While not a question in the survey, several respondents have taken the time to express that artifact signing is an important consideration to them.
Today, OpenTofu providers are signed with GPG keys and [there is an open issue about supporting Sigstore/Cosign](https://github.com/opentofu/opentofu/issues/307), which is blocked on the availability of a stable Go library to do so.
Today, OpenTofu providers are signed with GPG keys and [there is an open issue about supporting Sigstore/Cosign](https://github.com/opentofu/opentofu/issues/307), which is blocked on the availability of a stable Go library to do so. Another project worth some consideration is the [Notary Project](https://notaryproject.dev/) with similar aims to Sigstore/Cosign.
Modules are currently not signed in OpenTofu, which is a separate question to address. This consideration will, therefore, only address providers.

View File

@ -59,7 +59,7 @@ In this case, provider addresses matching `include` blocks would be redirected t
## Storage in OCI
OpenTofu takes some inspiration from how [ORAS](1-oci-primer.md#oras) stores files, but with a few key differences. It is our hope that [ORAS will soon support multi-arch images](https://github.com/oras-project/oras/issues/1053) and this implementation will be compatible.
OpenTofu takes some inspiration from how [ORAS](1-oci-primer.md#oras) stores files, but with a few key differences. It is our hope that [ORAS will soon support multi-platform images](https://github.com/oras-project/oras/issues/1053) and this implementation will be compatible.
1. Each OpenTofu provider OS and architecture (e.g. linux_amd64) will be stored as a ZIP file directly in an OCI blob. OpenTofu will not use tar files as it would be typical for a classic container image.
2. Each provider OS and architecture will have an image manifest with a single layer with the `mediaType` of `archive/zip` and the `org.opencontainers.image.title` annotation containing the original file name of the ZIP file.
@ -67,24 +67,28 @@ OpenTofu takes some inspiration from how [ORAS](1-oci-primer.md#oras) stores fil
4. The provider artifact must be tagged with the same version number as for the non-OCI use case. OpenTofu will ignore any versions it cannot identify as a semver version number, including the `latest` tag.
5. The index manifest may reference additional artifacts, such as SBOM manifests, under their corresponding MIME types. OpenTofu will ignore any artifacts without a known `artifactType`.
Additionally, the OS/architecture artifact may contain the following files as separate layers:
> [!NOTE]
> Provider version numbers may contain the `+` sign, such as `1.1.0+something`. This is not a valid OCI reference. OpenTofu will automatically translate the `+` sign to `_` and vice versa when creating or looking for OCI tags.
- `terraform-provider-YOURNAME_VERSION_PLATFORM_ARCH.zip.gpg` as `application/pgp-signature` containing the GPG Signature of the ZIP file. This file will currently be ignored by OpenTofu, but may be used at a later date.
- `terraform-provider-YOURNAME_VERSION_PLATFORM_ARCH.spdx.json` as `application/spdx+json` containing an SPDX SBOM file specific to this provider ZIP. This file will currently be ignored by OpenTofu, but may be used at a later date.
- `terraform-provider-YOURNAME_VERSION_PLATFORM_ARCH.intoto.jsonl` as `application/vnd.in-toto+json` containing an [in-toto attestation framework](https://github.com/in-toto/attestation)/[SLSA Provenance](https://slsa.dev/spec/v1.0/provenance) file for the OS/architecture ZIP. This file will currently be ignored by OpenTofu, but may be used at a later date.
- No additional files must be added as they may be used in future OpenTofu versions.
The index manifest may contain the following additional files as additional ORAS-style layers:
- `terraform-provider-YOURNAME.spdx.json` as `application/spdx+json` containing an SPDX SBOM file covering all OS/architecture combinations. This file will currently be ignored by OpenTofu, but may be used at a later date.
- `terraform-provider-YOURNAME.intoto.jsonl` as `application/vnd.in-toto+json` containing an [in-toto attestation framework](https://github.com/in-toto/attestation)/[SLSA Provenance](https://slsa.dev/spec/v1.0/provenance) file covering all OS/architecture combinations. This file will currently be ignored by OpenTofu, but may be used at a later date.
- `terraform-provider-YOURNAME_SHA256SUMS` as `text/plain+sha256sum` containing the checksums. If present, OpenTofu will download this file and refuse to use layers that don't match in their checksums.
- `terraform-provider-YOURNAME_SHA256SUMS.gpg` as `application/pgp-signature` containing the GPG signature of the SHA256SUMS file. This file will currently be ignored by OpenTofu, but may be used at a later date.
⚠ TODO: Does this make sense? Shouldn't we add this as an attached signature instead?
When necessary, you can attach artifacts containing signatures or attestations under a separate manifest using the `subject` field in the manifest. This will enable security tools like Trivy to automatically discover, for example, SBOMs.
> [!WARNING]
> Provider artifacts in OCI *must* be multi-arch images. OpenTofu will refuse to download and use non-multi-arch artifacts as provider images. In contrast, [modules](6-modules.md) *must* be non-multi-arch.
> As of this RFC, OpenTofu will not use these artifacts directly, but may do so in a later version based on the MIME type. This section describes the files we intend to use for mirroring below, but will not otherwise process in this release.
Manifests attached to a single platform manifest:
- `terraform-provider-YOURNAME_VERSION_PLATFORM_ARCH.zip.gpg` as `application/pgp-signature` containing the GPG Signature of the ZIP file.
- `terraform-provider-YOURNAME_VERSION_PLATFORM_ARCH.spdx.json` as `application/spdx+json` containing an SPDX SBOM file specific to this provider ZIP.
- `terraform-provider-YOURNAME_VERSION_PLATFORM_ARCH.intoto.jsonl` as `application/vnd.in-toto+json` containing an [in-toto attestation framework](https://github.com/in-toto/attestation)/[SLSA Provenance](https://slsa.dev/spec/v1.0/provenance) file for the OS/architecture ZIP.
For the top level (index) manifest:
- `terraform-provider-YOURNAME.spdx.json` as `application/spdx+json` containing an SPDX SBOM file covering all OS/architecture combinations.
- `terraform-provider-YOURNAME.intoto.jsonl` as `application/vnd.in-toto+json` containing an [in-toto attestation framework](https://github.com/in-toto/attestation)/[SLSA Provenance](https://slsa.dev/spec/v1.0/provenance) file covering all OS/architecture combinations.
- `terraform-provider-YOURNAME_SHA256SUMS` as `text/plain`, containing the SHA256 checksums for the individual platform ZIP files. Additionally, `terraform-provider-YOURNAME_SHA256SUMS.gpg` may be attached to the current file as `application/pgp-signature`.
> [!WARNING]
> Provider artifacts in OCI *must* have multi-platform (index) manifests. OpenTofu will refuse to download and use non-multi-platform artifacts as provider manifests. In contrast, [modules](6-modules.md) *must* have non-multi-platform manifests.
## Publishing or mirroring a provider
@ -93,7 +97,7 @@ Currently, there is no third-party tool capable of pushing an OCI artifact in th
1. Publish a set of ZIP files and related artifacts.
2. Directly mirror a provider from an existing OpenTofu registry.
In both cases we expect to find ZIP files that are [correctly named](https://search.opentofu.org/docs/providers/publishing#manually-for-the-adventurous) for providers, which will be published as individual multi-arch images. Additionally, the tool will process and upload any files matching file names described above.
In both cases we expect to find ZIP files that are [correctly named](https://search.opentofu.org/docs/providers/publishing#manually-for-the-adventurous) for providers, which will be published with individual multi-platform manifests. Additionally, the tool will process and upload any files matching file names described above.
The tool will also have a way to hook in external tools (such as [Syft](https://github.com/anchore/syft)) to generate SBOM files at the time of publication or mirroring.

View File

@ -9,28 +9,37 @@ This document is part of the [OCI registries RFC](../20241206-oci-registries.md)
---
In contrast to [providers](5-providers.md), modules already support schemes as part of their addresses. Therefore, modules will be addressable from OCI using the `oci+zip://` prefix in OpenTofu code directly. For example, you will be able to address an AWS ECR registry like this:
In contrast to [providers](5-providers.md), modules already support schemes as part of their addresses. Therefore, modules will be addressable from OCI using the `oci://` prefix in OpenTofu code directly. For example, you will be able to address an AWS ECR registry like this:
```hcl
module "foo" {
source="oci+zip://AWS_ACCOUNT_ID.dkr.ecr.REGION.amazonaws.com/REPOSITORY"
source="oci://AWS_ACCOUNT_ID.dkr.ecr.REGION.amazonaws.com/REPOSITORY"
}
```
By default, this will load the `latest` tag. If you would like to use specific version tags, you can specify the version separately:
By default, this will load the last stable version according to semantic versioning. If you would like to use specific version tags, you can specify the version separately:
```hcl
module "foo" {
source = "oci+zip://AWS_ACCOUNT_ID.dkr.ecr.REGION.amazonaws.com/REPOSITORY"
source = "oci://AWS_ACCOUNT_ID.dkr.ecr.REGION.amazonaws.com/REPOSITORY"
version = "1.1.0"
}
```
⚠ TODO: do we want to follow the git schema here or the version tag?
> [!NOTE]
> Module version numbers may contain the `+` sign, such as `1.1.0+something`. This is not a valid OCI reference. OpenTofu will automatically translate the `+` sign to `_` and vice versa when creating or looking for OCI tags.
You can also reference a folder inside a module:
```hcl
module "foo" {
source = "oci://AWS_ACCOUNT_ID.dkr.ecr.REGION.amazonaws.com/REPOSITORY//folder1/folder2"
}
```
## Artifact layout
Publishing modules in OpenTofu will be performed as a single, non-multi-arch ORAS-style artifact with the `artifactType` attribute as `application/vnd.opentofu.module`. OpenTofu will refuse to use multi-arch artifacts. Specifically:
Publishing modules in OpenTofu will be performed as a single, non-multi-platform ORAS-style artifact with the `artifactType` attribute as `application/vnd.opentofu.module`. OpenTofu will refuse to use multi-platform artifacts. Specifically:
1. The module must be packaged into a single ZIP file and published as a blob in OCI.
2. The main manifest is an image manifest (not an index manifest) and declares the `artifactType` of `application/vnd.opentofu.module` on the main manifest. The layer must have the `artifactType` of `archive/zip`.

View File

@ -26,19 +26,24 @@ oci {
## Integrated Docker mode
OpenTofu will support reading Docker configuration files, such as `~/.docker/config.json`, directly as requested by 53% of respondents in our survey. However, since 25% of respondents indicated that they want OpenTofu to not read Docker configuration files, this is an option that has to be explicitly enabled. You can do so by setting this option:
OpenTofu will support reading [Docker configuration files](https://github.com/moby/moby/blob/131e2bf12b2e1b3ee31b628a501f96bbb901f479/cliconfig/config.go#L49), such as `~/.docker/config.json`, directly as requested by 53% of respondents in our survey. However, since 25% of respondents indicated that they want OpenTofu to not read Docker configuration files, this is an option can be disabled. You can do so by setting this option:
```hcl
oci {
authentication {
use_docker = true
# Optional:
# docker_config_path = "~/.docker/config.json"
# Use the container engine configuration present on the current device.
# Defaults to: "auto"
# Possible values: "auto", "docker", "off
use_container_engine_authentication = "auto"
# Specify which configuration files to look for.
# Defaults to ["~/.docker/config.json"]
container_engine_config_paths = ["~/.docker/config.json"]
}
}
```
Setting this option will use Docker's stored credentials and configured credential helpers.
By default, OpenTofu will default to auto-detecting which container engine is present and use their configuration paths for credential helpers and credential helper configuration. OpenTofu users can disable this functionality by changing `use_container_engine_authentication = "off"`.
## Explicit mode
@ -47,14 +52,18 @@ Alternative to the integrated Docker mode, you can also specify credentials dire
```hcl
oci {
authentication {
use_container_engine_authentication = "off"
# Specify credentials explicitly for a host:
host "ghcr.io" {
token = "token-here"
# or:
domain "ghcr.io" {
# Authenticate with username and password:
username = "your-user"
password = "your-password"
# Use a domain-specific credentials helper:
docker_credentials_helper = "/path/to/credentials/helper"
}
# Optional, use Docker cred helper:
# Use a Docker cred helper:
docker_credentials_helper = "/path/to/credentials/helper"
}
}