Managing Trusted Image Registries

/etc/containers/registries.conf

  • Overridden by the user-related $HOME/.config/containers/registries.conf file if present
  • Manages a list of trusted registries that Podman can safely contact to search and pull images.

Let's look at an example of this file:

unqualified-search-registries = ["docker.io", "quay.io"]

[[registry]]
location = "registry.example.com:5000" 
insecure = false 
  • Podman accepts both unqualified and fully qualified images.

fully qualified

  • Includes a registry server FQDN, namespace, image name, and tag.
  • i.e. docker.io/library/nginx:latest
    • Has a full name that cannot be confused with any other Nginx image.

unqualified image

  • Only includes the image’s name.
  • i.e. nginx image can have multiple instances in the searched registries.
  • The majority of the images that result from the basic podman search nginx command will not be official and should be analyzed in detail to ensure they’re trusted.
    • Output can be filtered by the OFFICIAL flag and by the number of stars

Registry configuration file global settings

unqualified-search-registry

  • Defines the search list of registries for unqualified images.
  • When the user runs the podman search <image_name> command, Podman will search across the registries defined in this list.
  • By removing a registry from the list, Podman will stop searching the registry.
  • Podman will still be able to pull a fully qualified image from a foreign registry.

Registries and mirrors

[[registry]]

  • Manage single registries and create matching patterns for specific images.
  • The main settings of these tables:
    • prefix
      • Used to define the image names and can support multiple formats.
      • Can define images by following the host[:port]/namespace[/_namespace_…]/repo(:_tag|@digest) pattern.
      • Simpler patterns, such as host[:port], host[:port]/namespace, and even [*.]host, can be applied.
      • Users can define a generic prefix for a registry or a more detailed prefix to match a specific image or tag.
      • Given a fully qualified image, if two [[registry]] tables have a prefix with a partial match, the longest matching pattern will be used.
    • insecure
      • Boolean value
      • Allows unencrypted HTTP connections or TLS connections based on untrusted certificates.
    • blocked
      • This is a Boolean (true or false) that's used to define blocked registries. If it's set to true, the registries or images that match the prefix are blocked.
    • location
      • Defines the registry’s location.
      • By default, it is equal to prefix
      • A pattern that matches a custom prefix namespace will resolve to the location value.

[[registry.mirror]]

  • Provide alternate paths to the main registry or registry namespace.
  • When multiple mirrors are provided, Podman will search across them first and then fall back to the location that’s defined in the main [[registry]] table.

The following example extends the previous one by defining a namespaced registry entry and its mirror:

unqualified-search-registries = ["docker.io", "quay.io"]

[[registry]] 
location = "registry.example.com:5000/foo" 
insecure = false 

[[registry.mirror]] 
location = "mirror1.example.com:5000/bar" 

[[registry.mirror]] 
location = "mirror2.example.com:5000/bar" 

According to this example, if a user tries to pull the image tagged as registry.example.com:5000/foo/app:latest, Podman will try mirror1.example.com:5000/bar/app:latest, then mirror2.example.com:5000/bar/app:latest, and fall back to registry.example.com:5000/foo/app:latest in case a failure occurs.

Using a prefix provides even more flexibility. In the following example, all the images that match example.com/foo will be redirected to mirror locations and fall back to the main location at the end:

unqualified-search-registries = ["docker.io", "quay.io"] 

[[registry]] 
prefix = "example.com/foo" 
location = "registry.example.com:5000/foo" 
insecure = false 

[[registry.mirror]] 
location = "mirror1.example.com:5000/bar" 

[[registry.mirror]] 
location = "mirror2.example.com:5000/bar" 

In this example, when we pull the example.com/foo/app:latest image, Podman will attempt mirror1.example.com:5000/bar/app:latest, followed by mirror2.example.com:5000/bar/app:latest and registry.example.com:5000/foo/app:latest.

  • Possible to use mirroring for replacing public registries with private mirrors in disconnected environments.

The following example remaps the docker.io and quay.io registries to a private mirror with different namespaces:

[[registry]] 
prefix="quay.io" 
location="mirror-internal.example.com/quay" 

[[registry]] 
prefix="docker.io" 
location="mirror-internal.example.com/docker" 
  • Mirror registries should be kept up to date with mirrored repositories.

  • Administrators or SRE teams should implement an image sync policy to keep the repositories updated.

  • Can block a source that is not considered trusted.

    • Could impact a single image, a namespace, or a whole registry.

The following example tells Podman not to search for or pull images from a blocked registry:

[[registry]] 
location = "registry.rogue.io" 
blocked = true 
  • Can refine the blocking policy by passing a specific namespace without blocking the whole registry.

In the following example, every image search or pull that matches the quay.io/foo namespace pattern defined in the prefix field is blocked:

[[registry]] 
prefix = "quay.io/foo/" 
location = "quay.io" 
blocked = true 
  • Can define a very specific blocking rule for a single image or even a single tag by using the same approach that was described for namespaces.

Block a specific image tag:

[[registry]]
prefix = "internal-registry.example.com/dev/app:v0.1" 
location = "internal-registry.example.com " 
blocked = true 
  • It is possible to combine many blocking rules and add mirror tables on top of them.

  • A clever idea would be to keep the registry’s configuration file updated using configuration management tools and declaratively apply the registry’s filters.

Aliases

  • Fully qualified image names (FQNs) can become quite long if we sum up the registry FQDN, namespace(s), repository, and tags.
  • While using FQNs such as quay.io/podman/stable:latest is the gold standard for security and automation, they are often cumbersome to type manually.
  • To bridge the gap between convenience and security, Podman utilizes a short-name aliasing system.
  • Normally, when you provide an unqualified name (for example, podman pull fedora), Podman must iterate through a list of registries defined in the [registries.search] table of your configuration.
  • This can be slow and, if not configured correctly, potentially insecure.
  • Aliases change this behavior by short-circuiting the search.
  • If a short name matches an entry in an alias table, Podman immediately resolves it to the specific, fully qualified name provided in the mapping, bypassing the search registry list entirely.
  • On Fedora and RHEL, you don't have to build this list from scratch.
  • The system comes pre-configured with an extensive library of trusted mappings located at the following:
/etc/containers/registries.conf.d/000-shortnames.conf 
  • This file is maintained by the community and operating system vendors to ensure that common names point to their most logical and secure upstream sources.
  • For example, an entry in this file might look as follows:
[aliases] 
"fedora" = "registry.fedoraproject.org/fedora" 
"ubi8" = "registry.access.redhat.com/ubi8" 
"alpine" = "docker.io/library/alpine" 
  • When an alias matches a short name, it is immediately used without the registries defined in the unqualified-search-registries list being searched.
  • Can create custom files inside the /etc/containers/registries.conf.d/ folder to define aliases without bloating the main configuration file.
  • No tags or digests:
    • Aliases resolve the repository path, not a specific version.
    • For example, if you alias my-app to quay.io/org/my-app, running podman pull my-app:v2 will correctly resolve to quay.io/org/my-app:v2.
    • The alias handles the prefix, while the tag remains dynamic.
  • Precedence:
    • Local user-defined aliases (often found in $HOME/.config/containers/registries.conf.d/) will typically override the global system aliases found in /etc/containers/.