diff --git a/src/confcom/.gitignore b/src/confcom/.gitignore index fd6a06c13a0..d60f4d0f18a 100644 --- a/src/confcom/.gitignore +++ b/src/confcom/.gitignore @@ -23,8 +23,8 @@ ext_env/* # temporary shared libraries tests/outputs/** -az_extensions/confcom/azext_confcom/bin/ -az_extensions/confcom/azext_confcom/bin/* +azext_confcom/bin/ +azext_confcom/bin/* **/dmverity-vhd.exe **/dmverity-vhd # metadata file for coverage reports diff --git a/src/confcom/HISTORY.rst b/src/confcom/HISTORY.rst index 704f6f48388..95baa2b700b 100644 --- a/src/confcom/HISTORY.rst +++ b/src/confcom/HISTORY.rst @@ -2,6 +2,18 @@ Release History =============== +0.2.8 +* adding secureValue as a valid input for environment variables + +0.2.7 +* adding default mounts field for sidecars + +0.2.6 +* updating secretSource mount source to "plan9://" and adding vkMetrics and scKubeProxy to sidecar list + +0.2.5 +* removing default mounts and updating mount type to "bind" + 0.2.4 * updating sidecar package name and svn diff --git a/src/confcom/azext_confcom/custom.py b/src/confcom/azext_confcom/custom.py index f6bca707627..de7ec359334 100644 --- a/src/confcom/azext_confcom/custom.py +++ b/src/confcom/azext_confcom/custom.py @@ -129,7 +129,7 @@ def acipolicygen_confcom( exit_code = get_diff_outputs(policy, output_type == security_policy.OutputType.PRETTY_PRINT) elif not print_policy_to_terminal and arm_template: output = policy.get_serialized_output(output_type, use_json) - result = inject_policy_into_template(arm_template, output, count) + result = inject_policy_into_template(arm_template, arm_template_parameters, output, count) count += 1 if result: print("CCE Policy successfully injected into ARM Template") @@ -179,7 +179,6 @@ def get_diff_outputs(policy: security_policy.AciPolicy, outraw_pretty_print: boo print( "Existing policy and ARM Template match" - # TODO: verify this works if is_valid else formatted_output ) diff --git a/src/confcom/azext_confcom/template_util.py b/src/confcom/azext_confcom/template_util.py index d6ae0f7c0b1..6c08cdf6679 100644 --- a/src/confcom/azext_confcom/template_util.py +++ b/src/confcom/azext_confcom/template_util.py @@ -5,6 +5,7 @@ import re import json +import copy import tarfile from typing import Any, Tuple, Dict, List import deepdiff @@ -140,6 +141,9 @@ def process_env_vars_from_template(image_properties: dict) -> List[Dict[str, str ), config.ACI_FIELD_CONTAINERS_ENVS_VALUE: case_insensitive_dict_get( x, "value" + ) or + case_insensitive_dict_get( + x, "secureValue" ), config.ACI_FIELD_CONTAINERS_ENVS_STRATEGY: "string", } @@ -222,6 +226,8 @@ def get_values_for_params(input_parameter_json: dict, all_params: dict) -> Dict[ if case_insensitive_dict_get(all_params, key): all_params[key]["value"] = case_insensitive_dict_get( case_insensitive_dict_get(input_parameter_values_json, key), "value" + ) or case_insensitive_dict_get( + case_insensitive_dict_get(input_parameter_values_json, key), "secureValue" ) else: # parameter definition is in parameter file but not arm @@ -565,11 +571,13 @@ def compare_env_vars( def inject_policy_into_template( - arm_template_path: str, policy: str, count: int + arm_template_path: str, parameter_data_path: str, policy: str, count: int ) -> bool: write_flag = False + parameter_data = None input_arm_json = os_util.load_json_from_file(arm_template_path) - + if parameter_data_path: + parameter_data = os_util.load_json_from_file(arm_template_path) # find the image names and extract them from the template arm_resources = case_insensitive_dict_get( input_arm_json, config.ACI_FIELD_RESOURCES @@ -590,9 +598,7 @@ def inject_policy_into_template( ) resource = aci_list[count] - container_group_name = case_insensitive_dict_get( - resource, config.ACI_FIELD_RESOURCES_NAME - ) + container_group_properties = case_insensitive_dict_get( resource, config.ACI_FIELD_TEMPLATE_PROPERTIES ) @@ -616,6 +622,9 @@ def inject_policy_into_template( confidential_compute_properties[config.ACI_FIELD_TEMPLATE_CCE_POLICY] = policy write_flag = True else: + container_group_name = get_container_group_name( + input_arm_json, parameter_data, count + ) user_input = input( "Do you want to overwrite the CCE Policy currently in container group " + f'"{container_group_name}" in the ARM Template? (y/n) ' @@ -629,3 +638,61 @@ def inject_policy_into_template( os_util.write_json_to_file(arm_template_path, input_arm_json) return True return False + + +def get_container_group_name( + input_arm_json: dict, input_parameter_json: dict, count: int +) -> bool: + arm_json = copy.deepcopy(input_arm_json) + # extract variables and parameters in case we need to do substitutions + # while searching for image names + all_vars = case_insensitive_dict_get(arm_json, config.ACI_FIELD_TEMPLATE_VARIABLES) or {} + all_params = ( + case_insensitive_dict_get(arm_json, config.ACI_FIELD_TEMPLATE_PARAMETERS) or {} + ) + + if input_parameter_json: + # combine the parameter file into a single dictionary with the template parameters + input_parameter_values_json = case_insensitive_dict_get( + input_parameter_json, config.ACI_FIELD_TEMPLATE_PARAMETERS + ) + for key in input_parameter_values_json.keys(): + if case_insensitive_dict_get(all_params, key): + all_params[key]["value"] = case_insensitive_dict_get( + case_insensitive_dict_get(input_parameter_values_json, key), "value" + ) or case_insensitive_dict_get( + case_insensitive_dict_get(input_parameter_values_json, key), + "secureValue", + ) + else: + # parameter definition is in parameter file but not arm template + eprint( + f'Parameter ["{key}"] is empty or cannot be found in ARM template' + ) + # parameter file is missing field "parameters" + elif input_parameter_json and not input_parameter_values_json: + eprint( + f'Field ["{config.ACI_FIELD_TEMPLATE_PARAMETERS}"] is empty or cannot be found in Parameter file' + ) + + arm_json = parse_template(all_params, all_vars, arm_json) + # find the image names and extract them from the template + arm_resources = case_insensitive_dict_get(arm_json, config.ACI_FIELD_RESOURCES) + + if not arm_resources: + eprint(f"Field [{config.ACI_FIELD_RESOURCES}] is empty or cannot be found") + + aci_list = [ + item + for item in arm_resources + if item["type"] == config.ACI_FIELD_TEMPLATE_RESOURCE_LABEL + ] + + if not aci_list: + eprint( + f'Field ["type"] must contain value of ["{config.ACI_FIELD_TEMPLATE_RESOURCE_LABEL}"]' + ) + + resource = aci_list[count] + container_group_name = case_insensitive_dict_get(resource, config.ACI_FIELD_RESOURCES_NAME) + return container_group_name diff --git a/src/confcom/azext_confcom/tests/latest/README.md b/src/confcom/azext_confcom/tests/latest/README.md index d1d9329b752..10ed05b3ce1 100644 --- a/src/confcom/azext_confcom/tests/latest/README.md +++ b/src/confcom/azext_confcom/tests/latest/README.md @@ -34,7 +34,7 @@ test_arm_template_with_parameter_file_clean_room | mcr.microsoft.com/azure-funct test_policy_diff | rust:1.52.1 | See if the diff functionality outputs `True` when diffs match completely test_incorrect_policy_diff | rust:1.52.1 | Check output formatting and functionality of diff command test_update_infrastructure_svn | python:3.6.14-slim-buster | Change the minimum SVN for the insfrastructure fragment -test_multiple_policies | python:3.6.14-slim-buster & rust:1.52.1 | See if two unique policies are generated from a single ARM Template container multiple container groups. Also have an extra resource that is untouched +test_multiple_policies | python:3.6.14-slim-buster & rust:1.52.1 | See if two unique policies are generated from a single ARM Template container multiple container groups. Also have an extra resource that is untouched. Also has a secureValue for an environment variable. test_arm_template_with_init_container | python:3.6.14-slim-buster & rust:1.52.1 | See if having an initContainer is picked up and added to the list of valid containers ## policy.json [test file](test_confcom_scenario.py) diff --git a/src/confcom/azext_confcom/tests/latest/test_confcom_arm.py b/src/confcom/azext_confcom/tests/latest/test_confcom_arm.py index d2c1503df2d..6c0c9214e1e 100644 --- a/src/confcom/azext_confcom/tests/latest/test_confcom_arm.py +++ b/src/confcom/azext_confcom/tests/latest/test_confcom_arm.py @@ -1994,7 +1994,7 @@ class MultiplePolicyTemplate(unittest.TestCase): }, { "name": "TEST_REGEXP_ENV", - "value": "test_regexp_env" + "secureValue": "test_regexp_env" } ] } @@ -2051,7 +2051,7 @@ class MultiplePolicyTemplate(unittest.TestCase): "environmentVariables": [ { "name": "PATH", - "value": "/customized/different/path/value" + "secureValue": "/customized/different/path/value" } ] }