Skip to content

Commit 2a94604

Browse files
committed
Fetch docker.io credentials when building challenge images
Signed-off-by: Robert Detjens <[email protected]>
1 parent d91818f commit 2a94604

File tree

4 files changed

+111
-12
lines changed

4 files changed

+111
-12
lines changed

Cargo.lock

Lines changed: 14 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ minijinja = { version = "2.6.0", features = ["json"] }
4040
duct = "0.13.7"
4141
fastrand = "2.3.0"
4242
base64ct = { version = "1.7.3", features = ["alloc"] }
43+
docker_credential = "1.3.2"
4344

4445

4546
[dev-dependencies]

src/builder/docker.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use tempfile::Builder;
2020
use tokio;
2121
use tracing::{debug, error, info, trace, warn};
2222

23-
use crate::clients::docker;
23+
use crate::clients::{docker, docker_creds};
2424
use crate::configparser::challenge::BuildObject;
2525
use crate::configparser::UserPass;
2626

@@ -55,8 +55,12 @@ pub async fn build_image(
5555
.with_context(|| "could not create image context tarball")?;
5656
let tarball = tar.into_inner()?;
5757

58+
// fetch dockerhub creds from ~/.docker/auth.json for pull reasons
59+
// if creds fail to fetch, go anonymous
60+
let credentials = docker_creds()?;
61+
5862
// send to docker daemon
59-
let mut build_stream = client.build_image(build_opts, None, Some(tarball.into()));
63+
let mut build_stream = client.build_image(build_opts, Some(credentials), Some(tarball.into()));
6064

6165
// stream output to stdout
6266
while let Some(item) = build_stream.next().await {

src/clients.rs

Lines changed: 90 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
// Builders for the various client structs for Docker/Kube etc.
22

3-
use std::sync::OnceLock;
3+
use std::{collections::HashMap, sync::OnceLock};
44

5-
use anyhow::{anyhow, bail, Context, Error, Result};
5+
use anyhow::{anyhow, bail, Context, Result};
66
use bollard;
7-
use futures::TryFutureExt;
8-
use k8s_openapi::api::{
9-
apps::v1::Deployment,
10-
core::v1::{Pod, Service},
11-
networking::v1::Ingress,
12-
};
7+
use k8s_openapi::api::core::v1::Service;
138
use kube::{
149
self,
1510
api::{DynamicObject, GroupVersionKind, Patch, PatchParams},
@@ -48,6 +43,93 @@ pub async fn docker() -> Result<&'static bollard::Docker> {
4843
}
4944
}
5045

46+
/// Fetch registry login credentials from ~/.docker/config.json or $DOCKER_CONFIG
47+
///
48+
/// For now, this is only `docker.io` credentials, as it is the only registry
49+
/// that effectively requires auth for public images. We don't intend for
50+
/// challenge images to be built from private images.
51+
///
52+
/// If lookup fails, return empty hashmap as anonymous user.
53+
pub fn docker_creds() -> Result<HashMap<String, bollard::auth::DockerCredentials>> {
54+
let cred_r = docker_credential::get_credential("docker.io");
55+
56+
let cred = match cred_r {
57+
Ok(cred) => cred,
58+
Err(e) => {
59+
// dont die if the credentials could not be found. Warn and continue as anonymous
60+
warn!("could not fetch docker.io registry credentials from Docker config (are you logged in?)");
61+
// log full error for debug
62+
trace!("credentials error: {e:?}");
63+
64+
warn!("continuing as with anonymous build credentials");
65+
return Ok(HashMap::new());
66+
}
67+
};
68+
69+
// convert docker_credential enum to bollad
70+
let converted = match cred {
71+
docker_credential::DockerCredential::IdentityToken(token) => {
72+
bollard::auth::DockerCredentials {
73+
identitytoken: Some(token),
74+
..Default::default()
75+
}
76+
}
77+
docker_credential::DockerCredential::UsernamePassword(u, p) => {
78+
bollard::auth::DockerCredentials {
79+
username: Some(u),
80+
password: Some(p),
81+
..Default::default()
82+
}
83+
}
84+
};
85+
86+
Ok(std::collections::HashMap::from([(
87+
"docker.io".to_string(),
88+
converted,
89+
)]))
90+
}
91+
92+
// /// wip to pull all docker creds from json
93+
// pub async fn all_docker_creds() -> Result<HashMap<String, bollard::auth::DockerCredentials>> {
94+
// let auth_path = dirs::home_dir()
95+
// .expect("could not fetch homedir")
96+
// .join(".docker")
97+
// .join("config.json");
98+
// let auth_file = File::open(auth_path).context("could not read docker auth config.json")?;
99+
// // json is technically yaml so use the dependency we already bring in
100+
// let auth_json: serde_yml::Value = serde_yml::from_reader(auth_file).unwrap();
101+
102+
// let mut map = HashMap::new();
103+
// for (raw_reg, _raw_auth) in auth_json.get("auths").unwrap().as_mapping().unwrap() {
104+
// let reg = raw_reg.as_str().unwrap();
105+
// let cred = match engine_type().await {
106+
// EngineType::Docker => docker_credential::get_credential(reg),
107+
// EngineType::Podman => docker_credential::get_podman_credential(reg),
108+
// }
109+
// .context("could not fetch Docker registry credentials from Docker config")?;
110+
111+
// let creds = match cred {
112+
// docker_credential::DockerCredential::IdentityToken(token) => {
113+
// bollard::auth::DockerCredentials {
114+
// identitytoken: Some(token),
115+
// ..Default::default()
116+
// }
117+
// }
118+
// docker_credential::DockerCredential::UsernamePassword(u, p) => {
119+
// bollard::auth::DockerCredentials {
120+
// username: Some(u),
121+
// password: Some(p),
122+
// ..Default::default()
123+
// }
124+
// }
125+
// };
126+
127+
// map.insert(reg.to_string(), creds);
128+
// }
129+
130+
// Ok(map)
131+
// }
132+
51133
#[derive(Debug)]
52134
pub enum EngineType {
53135
Docker,

0 commit comments

Comments
 (0)