genpolicy: support arbitrary resources with -c

This allows passing config maps and secrets (as well as any other
resource kinds relevant in the future) using the -c flag.

Fixes: #10033

Co-authored-by: Leonard Cohnen <leonard.cohnen@gmail.com>
Signed-off-by: Leonard Cohnen <leonard.cohnen@gmail.com>
Signed-off-by: Aurélien Bombo <abombo@microsoft.com>
This commit is contained in:
Aurélien Bombo 2024-04-15 19:57:44 +00:00 committed by Markus Rudy
parent a286a5aee8
commit 4bb441965f
3 changed files with 66 additions and 16 deletions

View File

@ -438,6 +438,11 @@ pub struct SandboxData {
pub storages: Vec<agent::Storage>,
}
enum K8sEnvFromSource {
ConfigMap(config_map::ConfigMap),
Secret(secret::Secret),
}
impl AgentPolicy {
pub async fn from_files(config: &utils::Config) -> Result<AgentPolicy> {
let mut config_maps = Vec::new();
@ -488,9 +493,18 @@ impl AgentPolicy {
}
}
if let Some(config_map_files) = &config.config_map_files {
for file in config_map_files {
config_maps.push(config_map::ConfigMap::new(file)?);
if let Some(config_files) = &config.config_files {
for resource_file in config_files {
for config_resource in parse_config_file(resource_file.to_string(), config).await? {
match config_resource {
K8sEnvFromSource::ConfigMap(config_map) => {
config_maps.push(config_map);
}
K8sEnvFromSource::Secret(secret) => {
secrets.push(secret);
}
}
}
}
}
@ -822,6 +836,37 @@ fn get_image_layer_storages(
storages.push(overlay_storage);
}
async fn parse_config_file(
yaml_file: String,
config: &utils::Config,
) -> Result<Vec<K8sEnvFromSource>> {
let mut k8sRes = Vec::new();
let yaml_contents = yaml::get_input_yaml(&Some(yaml_file))?;
for document in serde_yaml::Deserializer::from_str(&yaml_contents) {
let doc_mapping = Value::deserialize(document)?;
if doc_mapping != Value::Null {
let yaml_string = serde_yaml::to_string(&doc_mapping)?;
let silent = config.silent_unsupported_fields;
let (mut resource, kind) = yaml::new_k8s_resource(&yaml_string, silent)?;
resource.init(config, &doc_mapping, silent).await;
// ConfigMap and Secret documents contain additional input for policy generation.
if kind.eq("ConfigMap") {
let config_map: config_map::ConfigMap = serde_yaml::from_str(&yaml_string)?;
debug!("{:#?}", &config_map);
k8sRes.push(K8sEnvFromSource::ConfigMap(config_map));
} else if kind.eq("Secret") {
let secret: secret::Secret = serde_yaml::from_str(&yaml_string)?;
debug!("{:#?}", &secret);
k8sRes.push(K8sEnvFromSource::Secret(secret));
}
}
}
Ok(k8sRes)
}
/// Converts the given name to a string representation of its sha256 hash.
fn name_to_hash(name: &str) -> String {
let mut hasher = Sha256::new();

View File

@ -18,10 +18,16 @@ struct CommandLineOptions {
#[clap(
short,
long,
help = "Optional Kubernetes config map YAML input file path"
help = "Optional Kubernetes config map YAML input file path. DEPRECATED: use --config-file instead"
)]
config_map_file: Option<String>,
#[clap(
long,
help = "Optional Kubernetes YAML input file path containing config resources such as ConfigMaps and Secrets"
)]
config_file: Option<Vec<String>>,
#[clap(
short = 'p',
long,
@ -111,7 +117,7 @@ pub struct Config {
pub yaml_file: Option<String>,
pub rego_rules_path: String,
pub settings: settings::Settings,
pub config_map_files: Option<Vec<String>>,
pub config_files: Option<Vec<String>>,
pub silent_unsupported_fields: bool,
pub raw_out: bool,
@ -125,16 +131,15 @@ impl Config {
pub fn new() -> Self {
let args = CommandLineOptions::parse();
let mut config_map_files = Vec::new();
if let Some(config_map_file) = &args.config_map_file {
config_map_files.push(config_map_file.clone());
}
// Migrate all files from the old `config_map_file` to the new `config_files` field
let config_files = args
.config_file
.unwrap_or_default()
.into_iter()
.chain(args.config_map_file.iter().cloned())
.collect::<Vec<_>>();
let cm_files = if !config_map_files.is_empty() {
Some(config_map_files.clone())
} else {
None
};
let config_files = (!config_files.is_empty()).then_some(config_files);
let mut layers_cache_file_path = args.layers_cache_file_path;
// preserve backwards compatibility for only using the `use_cached_files` flag
@ -151,7 +156,7 @@ impl Config {
yaml_file: args.yaml_file,
rego_rules_path: args.rego_rules_path,
settings,
config_map_files: cm_files,
config_files,
silent_unsupported_fields: args.silent_unsupported_fields,
raw_out: args.raw_out,
base64_out: args.base64_out,

View File

@ -85,7 +85,7 @@ mod tests {
let config = genpolicy::utils::Config {
base64_out: false,
config_map_files: None,
config_files: None,
containerd_socket_path: None, // Some(String::from("/var/run/containerd/containerd.sock")),
insecure_registries: Vec::new(),
layers_cache_file_path: None,