Skip to content

Commit

Permalink
[confcom] updating diff mode and adding cs2 (#7500)
Browse files Browse the repository at this point in the history
* making diff mode more robust

* fixing bug when trying to do regex via parameters

* changing how seccompProfile is interacted with in the template

* adding configmaps as a possible source of information from ARM template

* adding cs2
  • Loading branch information
SethHollandsworth committed Apr 19, 2024
1 parent 1871d35 commit ea2fb8e
Show file tree
Hide file tree
Showing 14 changed files with 338 additions and 109 deletions.
9 changes: 9 additions & 0 deletions src/confcom/HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@
Release History
===============
0.3.5
++++++
* making diff mode more robust
* bugfix for arm template regex
* updating genpolicy version up through 3.2.0.azl0.genpolicy1
* adding configmap sidecar
* bugfix for seccompProfile missing after injecting policy
* adding cs2 support

0.3.4
++++++
* adding faster hashing flag to use buffered reader in dmverity-vhd
Expand Down
12 changes: 11 additions & 1 deletion src/confcom/azext_confcom/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
ACI_FIELD_RESOURCES = "resources"
ACI_FIELD_RESOURCES_NAME = "name"
ACI_FIELD_CONTAINERS = "containers"
ACI_FIELD_CONTAINERS_NAME = "name"
ACI_FIELD_CONTAINERS_CONTAINERIMAGE = "containerImage"
ACI_FIELD_CONTAINERS_ENVS = "environmentVariables"
ACI_FIELD_CONTAINERS_ENVS_NAME = "name"
Expand All @@ -36,6 +37,8 @@
ACI_FIELD_CONTAINERS_REGO_FRAGMENTS_MINIMUM_SVN = "minimumSvn"
ACI_FIELD_CONTAINERS_REGO_FRAGMENTS_INCLUDES = "includes"
ACI_FIELD_CONTAINERS_ID = "id"
ACI_FIELD_CONTAINERS_CONFIGMAP = "configMap"
ACI_FIELD_CONTAINERS_CONFIGMAP_KEYVALUE = "keyValuePairs"

ACI_FIELD_CONTAINERS_ARCHITECTURE_KEY = "Architecture"
ACI_FIELD_CONTAINERS_ARCHITECTURE_VALUE = "amd64"
Expand All @@ -58,6 +61,7 @@
ACI_FIELD_TEMPLATE_IMAGE = "image"
ACI_FIELD_TEMPLATE_SECURITY_CONTEXT = "securityContext"
ACI_FIELD_TEMPLATE_RESOURCE_LABEL = "Microsoft.ContainerInstance/containerGroups"
ACI_FIELD_TEMPLATE_RESOURCE_PROFILE_LABEL = "Microsoft.ContainerInstance/containerGroupProfiles"
ACI_FIELD_TEMPLATE_COMMAND = "command"
ACI_FIELD_TEMPLATE_ENVS = "environmentVariables"
ACI_FIELD_TEMPLATE_VOLUME_MOUNTS = "volumeMounts"
Expand All @@ -70,10 +74,14 @@
ACI_FIELD_CONTAINERS_CAPABILITIES = "capabilities"
ACI_FIELD_CONTAINERS_CAPABILITIES_ADD = "add"
ACI_FIELD_CONTAINERS_CAPABILITIES_DROP = "drop"

ACI_FIELD_SUPPORTED_RESOURCES = [
ACI_FIELD_TEMPLATE_RESOURCE_LABEL,
ACI_FIELD_TEMPLATE_RESOURCE_PROFILE_LABEL
]

# output json values
POLICY_FIELD_CONTAINERS = "containers"
POLICY_FIELD_CONTAINERS_NAME = "name"
POLICY_FIELD_CONTAINERS_ID = "id"
POLICY_FIELD_CONTAINERS_ELEMENTS = "elements"
POLICY_FIELD_CONTAINERS_LENGTH = "length"
Expand Down Expand Up @@ -116,6 +124,8 @@
POLICY_FIELD_CONTAINERS_ELEMENTS_REGO_FRAGMENTS_ISS = "iss"
POLICY_FIELD_CONTAINERS_ELEMENTS_REGO_FRAGMENTS_MINIMUM_SVN = "minimum_svn"
POLICY_FIELD_CONTAINERS_ELEMENTS_REGO_FRAGMENTS_INCLUDES = "includes"
POLICY_FIELD_CONTAINERS_ELEMENTS_MOUNTS_CONFIGMAP_LOCATION = "/mnt/configmap"
POLICY_FIELD_CONTAINERS_ELEMENTS_MOUNTS_CONFIGMAP_TYPE = "emptyDir"

CONFIG_FILE = "./data/internal_config.json"

Expand Down
14 changes: 14 additions & 0 deletions src/confcom/azext_confcom/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ def extract_id(container_json: Any) -> str:
return case_insensitive_dict_get(container_json, config.ACI_FIELD_CONTAINERS_ID)


def extract_container_name(container_json: Any) -> str:
return case_insensitive_dict_get(container_json, config.ACI_FIELD_CONTAINERS_NAME)


def extract_working_dir(container_json: Any) -> str:
# parse working directory
workingDir = case_insensitive_dict_get(
Expand Down Expand Up @@ -488,6 +492,7 @@ def from_json(

container_image = extract_container_image(container_json)
id_val = extract_id(container_json)
container_name = extract_container_name(container_json)
environment_rules = extract_env_rules(container_json=container_json)
command = extract_command(container_json)
working_dir = extract_working_dir(container_json)
Expand All @@ -507,6 +512,7 @@ def from_json(
allow_privilege_escalation = extract_allow_privilege_escalation(container_json)
return ContainerImage(
containerImage=container_image,
containerName=container_name,
environmentRules=environment_rules,
command=command,
workingDir=working_dir,
Expand Down Expand Up @@ -540,8 +546,10 @@ def __init__(
allowPrivilegeEscalation: bool = True,
execProcesses: List = None,
signals: List = None,
containerName: str = ""
) -> None:
self.containerImage = containerImage
self.containerName = containerName
if ":" in containerImage:
self.base, self.tag = containerImage.split(":", 1)
else:
Expand Down Expand Up @@ -573,6 +581,9 @@ def get_policy_json(self) -> str:
def get_id(self) -> str:
return self._identifier

def get_name(self) -> str:
return self.containerName

def get_working_dir(self) -> str:
return self._workingDir

Expand Down Expand Up @@ -616,6 +627,8 @@ def set_extra_environment_rules(self, rules: Dict) -> None:
def parse_all_parameters_and_variables(self, params, vars_dict) -> None:
field_names = [
"containerImage",
"containerName",
"_identifier",
"_environmentRules",
"_command",
"_workingDir",
Expand Down Expand Up @@ -696,6 +709,7 @@ def _populate_policy_json_elements(self) -> Dict[str, Any]:

elements = {
config.POLICY_FIELD_CONTAINERS_ID: self._identifier,
config.POLICY_FIELD_CONTAINERS_NAME: self.get_name(),
config.POLICY_FIELD_CONTAINERS_ELEMENTS_LAYERS: self._layers,
config.POLICY_FIELD_CONTAINERS_ELEMENTS_COMMANDS: self._command,
config.POLICY_FIELD_CONTAINERS_ELEMENTS_ENVS: self._get_environment_rules(),
Expand Down
4 changes: 1 addition & 3 deletions src/confcom/azext_confcom/custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,8 @@ def acipolicygen_confcom(
elif diff:
exit_code = get_diff_outputs(policy, output_type == security_policy.OutputType.PRETTY_PRINT)
elif arm_template and not (print_policy_to_terminal or outraw or outraw_pretty_print):
seccomp_profile_hashes = {x.get_id(): x.get_seccomp_profile_sha256() for x in policy.get_images()}
result = inject_policy_into_template(arm_template, arm_template_parameters,
policy.get_serialized_output(), count,
seccomp_profile_hashes)
policy.get_serialized_output(), count)
if result:
# this is always going to be the unencoded policy
print(str_to_sha256(policy.get_serialized_output(OutputType.RAW)))
Expand Down
5 changes: 3 additions & 2 deletions src/confcom/azext_confcom/data/internal_config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.3.4",
"version": "0.3.5",
"hcsshim_config": {
"maxVersion": "1.0.0",
"minVersion": "0.0.1"
Expand Down Expand Up @@ -169,7 +169,8 @@
"mcr.microsoft.com/aci/atlas-mount-gitrepo-volume",
"k8s.gcr.io/pause",
"mcr.microsoft.com/aci/sc-proxy",
"mcr.microsoft.com/aci/vk-metrics-sidecar"
"mcr.microsoft.com/aci/vk-metrics-sidecar",
"mcr.microsoft.com/aci/configmaps-adapter-linux"
],
"default_rego_fragments": [
{
Expand Down
19 changes: 9 additions & 10 deletions src/confcom/azext_confcom/os_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,23 +145,22 @@ def map_image_from_tar(image_name: str, tar: TarFile, tar_location: str):
tar_dir = os.path.dirname(tar_location)
info_file = None
info_file_name = "manifest.json"
# if there's more than one image in the tarball, we need to do some more logic
if len(info_file_name) > 0:
# extract just the manifest file and see if any of the RepoTags match the image_name we're searching for
# the manifest.json should have a list of all the image tags
# and what json files they map to to get env vars, startup cmd, etc.
tar.extract(info_file_name, path=tar_dir)
manifest_path = os.path.join(tar_dir, info_file_name)
manifest = load_json_from_file(manifest_path)

# extract just the manifest file and see if any of the RepoTags match the image_name we're searching for
# the manifest.json should have a list of all the image tags
# and what json files they map to to get env vars, startup cmd, etc.
tar.extract(info_file_name, path=tar_dir)
manifest_path = os.path.join(tar_dir, info_file_name)
manifest = load_json_from_file(manifest_path)
try:
# if we match a RepoTag to the image, stop searching
for image in manifest:
if image_name in image.get("RepoTags"):
info_file = image.get("Config")
break
finally:
# remove the extracted manifest file to clean up
os.remove(manifest_path)
else:
eprint(f"Tarball at {tar_location} contains no images")

if not info_file:
return None
Expand Down
Loading

0 comments on commit ea2fb8e

Please sign in to comment.