1
0
Fork 0
mirror of https://github.com/imjasonh/krust synced 2026-07-18 06:56:13 +00:00

feat: Implement registry authentication support

This implements authentication for container registries, porting
functionality from go-containerregistry's authn package to Rust.

Key features:
- AuthConfig struct for various auth types (basic, bearer, anonymous)
- Authenticator trait for pluggable auth providers
- DefaultKeychain that reads Docker config files from standard locations
- Support for credential helpers (docker-credential-*)
- Integration with oci-distribution for registry operations

The implementation checks for credentials in this order:
1. DOCKER_CONFIG environment variable
2. REGISTRY_AUTH_FILE environment variable
3. XDG_RUNTIME_DIR/containers/auth.json
4. HOME/.docker/config.json

Credential helpers are supported if configured in the Docker config.

This enables krust to:
- Pull private base images
- Push to authenticated registries
- Support various auth methods (basic, token, oauth2)

Closes #2

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Jason Hall 2025-06-08 09:19:04 -04:00
parent 5acbc21b3f
commit b6b0c71d0c
Failed to extract signature
8 changed files with 898 additions and 12 deletions

View file

@ -10,14 +10,12 @@ mod tests;
pub struct RegistryClient {
client: Client,
#[allow(dead_code)]
auth: RegistryAuth,
}
impl RegistryClient {
pub fn new(auth: RegistryAuth) -> Result<Self> {
pub fn new() -> Result<Self> {
let client = Client::new(oci_distribution::client::ClientConfig::default());
Ok(Self { client, auth })
Ok(Self { client })
}
pub async fn push_image(
@ -25,6 +23,7 @@ impl RegistryClient {
image_ref: &str,
config_data: Vec<u8>,
layers: Vec<(Vec<u8>, String)>,
auth: &RegistryAuth,
) -> Result<(String, usize)> {
let reference: Reference = image_ref
.parse()
@ -32,6 +31,12 @@ impl RegistryClient {
info!("Pushing image to {}", reference);
// Authenticate with the registry
self.client
.auth(&reference, auth, oci_distribution::RegistryOperation::Push)
.await
.context("Failed to authenticate with registry")?;
// Push config blob
let config_digest = format!("sha256:{}", sha256::digest(&config_data));
debug!("Pushing config blob: {}", config_digest);
@ -110,10 +115,17 @@ impl RegistryClient {
&mut self,
image_ref: &str,
manifest_descriptors: Vec<crate::manifest::ManifestDescriptor>,
auth: &RegistryAuth,
) -> Result<String> {
let reference = Reference::from_str(image_ref)
.context(format!("Failed to parse image reference: {}", image_ref))?;
// Authenticate with the registry
self.client
.auth(&reference, auth, oci_distribution::RegistryOperation::Push)
.await
.context("Failed to authenticate with registry")?;
// Create the image index
let index = crate::manifest::ImageIndex::new(manifest_descriptors);
@ -180,7 +192,11 @@ impl RegistryClient {
}
/// Fetch the manifest for an image and extract available platforms
pub async fn get_image_platforms(&mut self, image_ref: &str) -> Result<Vec<String>> {
pub async fn get_image_platforms(
&mut self,
image_ref: &str,
auth: &RegistryAuth,
) -> Result<Vec<String>> {
let reference: Reference = image_ref
.parse()
.context("Failed to parse image reference")?;
@ -190,7 +206,7 @@ impl RegistryClient {
// Pull the manifest
let (manifest, _) = self
.client
.pull_manifest(&reference, &self.auth)
.pull_manifest(&reference, auth)
.await
.context("Failed to pull manifest")?;