Skip to content

Auth registry for authenticated pull - #112

Open
HarshwardhanPatil07 wants to merge 6 commits into
bootc-dev:mainfrom
HarshwardhanPatil07:auth-registry
Open

Auth registry for authenticated pull#112
HarshwardhanPatil07 wants to merge 6 commits into
bootc-dev:mainfrom
HarshwardhanPatil07:auth-registry

Conversation

@HarshwardhanPatil07

@HarshwardhanPatil07 HarshwardhanPatil07 commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Adds a second registry instance (bink-auth-registry) configured with htpasswd authentication. This registry shares the same storage volume as the existing unauthenticated registry, ensuring that images pushed to localhost:5000 are immediately available on localhost:5001 with credentials, without any data duplication.

Verification steps:

1. Build and start

make build-bink
./bink cluster start --cluster-name test --api-port 0

2. Push an image to the unauthenticated registry

podman pull quay.io/libpod/busybox:latest
podman tag quay.io/libpod/busybox:latest localhost:5000/busybox:test
podman push --tls-verify=false localhost:5000/busybox:test

3. Verify auth works

curl -s http://localhost:5001/v2/_catalog # → 401 (blocked)
curl -s -u testuser:testpassword http://localhost:5001/v2/_catalog # → {"repositories":["busybox"]}

4. Clean up

./bink cluster stop --cluster-name test --remove-data

closes #101

…rage

Docker Distribution requires a shared REGISTRY_HTTP_SECRET when
multiple registry instances access the same storage backend. Add the
secret to the existing unauthenticated registry in preparation for
the authenticated registry that will share the same volume.

Signed-off-by: HarshwardhanPatil07 <harshpat@redhat.com>
@HarshwardhanPatil07

Copy link
Copy Markdown
Collaborator Author

cc @alicefr @Johan-Liebert1

Add a second registry instance (bink-auth-registry) that shares the
same bink-registry-data volume as the unauthenticated registry. The
auth registry mounts the volume read-only and requires htpasswd
authentication with fixed test credentials (testuser/testpassword).

This enables bootc-operator milestone 5b (pull secret propagation)
e2e tests that need a pull-secret-protected registry without breaking
the existing development workflow on the unauthenticated registry.

The auth registry listens on port 5001 with static IP 10.88.0.3 on
the podman default network. Volume sharing between two registry:2
instances is safe: the filesystem driver uses atomic renames with no
file locks, and the read-only instance sees new images immediately.

Credentials are configured via htpasswd with bcrypt hashing, injected
at container startup through an entrypoint override. The bcrypt hash
is generated at runtime using golang.org/x/crypto/bcrypt.

Assisted-by: AI
Signed-off-by: HarshwardhanPatil07 <harshpat@redhat.com>

@Johan-Liebert1 Johan-Liebert1 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks sane

Comment thread internal/cli/registry/stop.go Outdated
Comment thread internal/cli/registry/stop.go Outdated
return nil
}

if err := mgr.StopAuthRegistry(cmd.Context()); err != nil {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, we're stopping the AuthRegistry regardless it was created or not. Are we sure this won't just error out if the auth registry doesn't exist?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

both registries are created by default. it doesn't error out.
Experimentation :

harshpat@harshpat-thinkpadp1gen4i:~/Downloads/repos/bink$ podman rm -f bink-auth-registry
harshpat@harshpat-thinkpadp1gen4i:~/Downloads/repos/bink$ ./bink registry info
Registry (unauthenticated): running
  IP:        10.88.0.2
  Host port: 5000
  Push:      podman push --tls-verify=false localhost:5000/<image>:<tag>
  Pull:      registry.cluster.local:5000/<image>:<tag>

Registry (authenticated):   stopped
  IP:          10.88.0.3
  Host port:   5001
  Pull:        auth-registry.cluster.local:5001/<image>:<tag>
  Credentials: testuser / testpassword
harshpat@harshpat-thinkpadp1gen4i:~/Downloads/repos/bink$ ./bink registry stop
harshpat@harshpat-thinkpadp1gen4i:~/Downloads/repos/bink$ ./bink registry info
Registry (unauthenticated): stopped
  IP:        10.88.0.2
  Host port: 5000
  Push:      podman push --tls-verify=false localhost:5000/<image>:<tag>
  Pull:      registry.cluster.local:5000/<image>:<tag>

Registry (authenticated):   stopped
  IP:          10.88.0.3
  Host port:   5001
  Pull:        auth-registry.cluster.local:5001/<image>:<tag>
  Credentials: testuser / testpassword
harshpat@harshpat-thinkpadp1gen4i:~/Downloads/repos/bink$ ./bink registry start
harshpat@harshpat-thinkpadp1gen4i:~/Downloads/repos/bink$ ./bink registry info
Registry (unauthenticated): running
  IP:        10.88.0.2
  Host port: 5000
  Push:      podman push --tls-verify=false localhost:5000/<image>:<tag>
  Pull:      registry.cluster.local:5000/<image>:<tag>

Registry (authenticated):   running
  IP:          10.88.0.3
  Host port:   5001
  Pull:        auth-registry.cluster.local:5001/<image>:<tag>
  Credentials: testuser / testpassword
harshpat@harshpat-thinkpadp1gen4i:~/Downloads/repos/bink$ podman rm -f bink-auth-registry
bink-auth-registry
harshpat@harshpat-thinkpadp1gen4i:~/Downloads/repos/bink$ ./bink registry info
Registry (unauthenticated): running
  IP:        10.88.0.2
  Host port: 5000
  Push:      podman push --tls-verify=false localhost:5000/<image>:<tag>
  Pull:      registry.cluster.local:5000/<image>:<tag>

Registry (authenticated):   stopped
  IP:          10.88.0.3
  Host port:   5001
  Pull:        auth-registry.cluster.local:5001/<image>:<tag>
  Credentials: testuser / testpassword

Comment thread internal/node/cloudinit_test.go Outdated
Comment thread internal/node/cloudinit_test.go Outdated
Comment thread internal/node/cloudinit_test.go
return fmt.Errorf("ensuring registry image: %w", err)
}

if err := m.podman.VolumeCreate(ctx, config.RegistryVolume, nil); err != nil {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is VolumeCreate idempotent? Would this fail if the container already exists?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it doesn't fail
Experimentation:

harshpat@harshpat-thinkpadp1gen4i:~/Downloads/repos/bink$ ./bink registry start
harshpat@harshpat-thinkpadp1gen4i:~/Downloads/repos/bink$ podman volume inspect bink-registry-data --format "{{.Name}}"
bink-registry-data
harshpat@harshpat-thinkpadp1gen4i:~/Downloads/repos/bink$ ./bink registry start
harshpat@harshpat-thinkpadp1gen4i:~/Downloads/repos/bink$ ./bink registry stop --auth
harshpat@harshpat-thinkpadp1gen4i:~/Downloads/repos/bink$ ./bink registry start --auth

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add DNS resolution for auth-registry.cluster.local and configure
CRI-O and containers/registries.conf inside VMs to treat the
authenticated registry at port 5001 as an insecure (HTTP) registry.

The DNS entry is baked into the DNS container image and requires a
rebuild via make build-dns-image.

Assisted-by: AI
Signed-off-by: HarshwardhanPatil07 <harshpat@redhat.com>
Start the authenticated registry automatically during cluster start
alongside the unauthenticated one. Update the registry CLI subcommands:

- bink registry start: starts both registries (--auth for auth only)
- bink registry stop: stops both registries and removes data
  (--auth to stop only the authenticated registry)
- bink registry info: shows status of both registries with credentials
- bink cluster stop --remove-data: updated note mentioning both
  registries

Assisted-by: AI
Signed-off-by: HarshwardhanPatil07 <harshpat@redhat.com>
The REGISTRY_STORAGE_MAINTENANCE_READONLY_ENABLED env var causes a
panic in Docker Distribution because its config parser cannot handle
the deeply nested storage.maintenance.readonly.enabled key via
environment variable flattening. The volume is already mounted
read-only (ro option), so push attempts will fail at the filesystem
level regardless.

Assisted-by: AI
Signed-off-by: HarshwardhanPatil07 <harshpat@redhat.com>
Comment thread internal/registry/registry.go Outdated
return fmt.Errorf("ensuring registry image: %w", err)
}

if err := m.podman.VolumeCreate(ctx, config.RegistryVolume, nil); err != nil {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if this volume already exist? Will this error out?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VolumeCreate is idempotent — it catches "volume already exists" errors and returns nil (podman/client.go:738). Verified locally: calling bink registry start twice in a row completes without error.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/bootc-dev/bink/blob/main/internal/podman/client.go#L739-L741
So if the volume exists podman does returns the error "volume already exists", our code catches that specific error and returns nil

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Experimentation:

harshpat@harshpat-thinkpadp1gen4i:~/Downloads/repos/bink$ ./bink registry start
harshpat@harshpat-thinkpadp1gen4i:~/Downloads/repos/bink$ podman volume inspect bink-registry-data --format "{{.Name}}"
bink-registry-data
harshpat@harshpat-thinkpadp1gen4i:~/Downloads/repos/bink$ ./bink registry start
harshpat@harshpat-thinkpadp1gen4i:~/Downloads/repos/bink$ ./bink registry stop --auth
harshpat@harshpat-thinkpadp1gen4i:~/Downloads/repos/bink$ ./bink registry start --auth

Comment thread internal/registry/registry.go Outdated
@alicefr

alicefr commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

@HarshwardhanPatil07 thanks for the work, would you mind to add an integration test. Like push an image and try to pull it using the secret registry and authentication. Thanks!

If a container is removed between the ContainerExists check and the
ContainerRemove call (e.g. by another process or a parallel test),
the remove returns a "no such container" error. Treat this as a
no-op instead of a hard failure, so the stop flow completes
gracefully.

Assisted-by: AI
Signed-off-by: HarshwardhanPatil07 <harshpat@redhat.com>
@HarshwardhanPatil07

Copy link
Copy Markdown
Collaborator Author

Thank you very much for the amazing reviews @alicefr @Johan-Liebert1. If you have more questions please do let me know

@HarshwardhanPatil07

Copy link
Copy Markdown
Collaborator Author

Yes @alicefr, I will create test in follow up PR to keep it clean

@alicefr

alicefr commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Yes @alicefr, I will create test in follow up PR to keep it clean

Please, include it in this PR so we can check if the code is correct

@HarshwardhanPatil07

Copy link
Copy Markdown
Collaborator Author

@alicefr Yes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Configure the registry with a secret

3 participants