1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use k8s_openapi::api::core::v1::Secret;
use kube::api::Api;
use oci_distribution::secrets::RegistryAuth;
pub struct RegistryAuthResolver {
kube_client: kube::Client,
pod_namespace: String,
image_pull_secret_names: Vec<String>,
}
impl RegistryAuthResolver {
pub fn new(client: kube::Client, pod: &crate::pod::Pod) -> Self {
RegistryAuthResolver {
kube_client: client,
pod_namespace: pod.namespace().to_owned(),
image_pull_secret_names: pod.image_pull_secrets(),
}
}
pub async fn resolve_registry_auth(
&self,
reference: &oci_distribution::Reference,
) -> anyhow::Result<RegistryAuth> {
let secrets_api: Api<Secret> =
Api::namespaced(self.kube_client.clone(), &self.pod_namespace);
let secret_futures: Vec<_> = self
.image_pull_secret_names
.iter()
.map(|name| secrets_api.get(name))
.collect();
let secret_results = futures::future::join_all(secret_futures).await;
for secret_result in secret_results {
match secret_result {
Err(e) => return Err(e.into()),
Ok(secret) => {
if let Some(auth) = parse_auth(&secret, reference.registry()) {
return Ok(auth);
}
}
}
}
Ok(RegistryAuth::Anonymous)
}
}
fn parse_auth(secret: &Secret, registry_name: &str) -> Option<RegistryAuth> {
if let Some(data) = secret.data.as_ref() {
parse_auth_from_secret_data(data, registry_name)
} else {
None
}
}
fn parse_auth_from_secret_data(
secret_data: &std::collections::BTreeMap<String, k8s_openapi::ByteString>,
registry_name: &str,
) -> Option<RegistryAuth> {
secret_data
.values()
.find_map(|v| parse_auth_from_secret_value(v, registry_name))
}
fn parse_auth_from_secret_value(
secret_value: &k8s_openapi::ByteString,
registry_name: &str,
) -> Option<RegistryAuth> {
parse_byte_string_json(secret_value)
.and_then(|value| parse_auth_from_json_value(&value, registry_name))
}
fn parse_byte_string_json(byte_string: &k8s_openapi::ByteString) -> Option<serde_json::Value> {
serde_json::from_slice(&byte_string.0).ok()
}
fn parse_auth_from_json_value(
json_value: &serde_json::Value,
registry_name: &str,
) -> Option<RegistryAuth> {
json_value
.get("auths")
.and_then(|auths| auths.get(registry_name))
.and_then(|creds| parse_auth_from_json_creds(creds))
}
fn parse_auth_from_json_creds(json_creds: &serde_json::Value) -> Option<RegistryAuth> {
let username = json_creds.get("username");
let password = json_creds.get("password");
match (username, password) {
(Some(serde_json::Value::String(u)), Some(serde_json::Value::String(p))) => {
Some(RegistryAuth::Basic(u.to_owned(), p.to_owned()))
}
_ => None,
}
}